winspool: Manage loaded monitors in a list.
[wine.git] / dlls / winspool.drv / info.c
blob45f705448e1eab6433ecc894c28c8ad5aed628c6
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
9 * Copyright 2005, 2006 Detlef Riekenberg
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "config.h"
27 #include "wine/port.h"
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <stddef.h>
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif
38 #include <signal.h>
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
41 # ifndef SONAME_LIBCUPS
42 # define SONAME_LIBCUPS "libcups.so"
43 # endif
44 #endif
46 #define NONAMELESSUNION
47 #define NONAMELESSSTRUCT
48 #include "wine/library.h"
49 #include "windef.h"
50 #include "winbase.h"
51 #include "winuser.h"
52 #include "winerror.h"
53 #include "winreg.h"
54 #include "wingdi.h"
55 #include "winspool.h"
56 #include "winternl.h"
57 #include "wine/windef16.h"
58 #include "wine/unicode.h"
59 #include "wine/debug.h"
60 #include "wine/list.h"
61 #include "heap.h"
62 #include "winnls.h"
64 #include "ddk/winsplp.h"
65 #include "wspool.h"
67 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
69 /* ############################### */
71 static CRITICAL_SECTION monitor_handles_cs;
72 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
74 0, 0, &monitor_handles_cs,
75 { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
76 0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
78 static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
81 static CRITICAL_SECTION printer_handles_cs;
82 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
84 0, 0, &printer_handles_cs,
85 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
86 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
88 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
90 /* ############################### */
92 typedef struct {
93 struct list entry;
94 LPWSTR name;
95 LPWSTR dllname;
96 PMONITORUI monitorUI;
97 LPMONITOR monitor;
98 HMODULE hdll;
99 DWORD refcount;
100 DWORD dwMonitorSize;
101 } monitor_t;
103 typedef struct {
104 DWORD job_id;
105 HANDLE hf;
106 } started_doc_t;
108 typedef struct {
109 struct list jobs;
110 LONG ref;
111 } jobqueue_t;
113 typedef struct {
114 LPWSTR name;
115 jobqueue_t *queue;
116 started_doc_t *doc;
117 } opened_printer_t;
119 typedef struct {
120 struct list entry;
121 DWORD job_id;
122 WCHAR *filename;
123 WCHAR *document_title;
124 } job_t;
127 typedef struct {
128 LPCWSTR envname;
129 LPCWSTR subdir;
130 DWORD driverversion;
131 LPCWSTR versionregpath;
132 LPCWSTR versionsubdir;
133 } printenv_t;
135 /* ############################### */
137 static struct list monitor_handles = LIST_INIT( monitor_handles );
139 static opened_printer_t **printer_handles;
140 static int nb_printer_handles;
141 static LONG next_job_id = 1;
143 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
144 WORD fwCapability, LPSTR lpszOutput,
145 LPDEVMODEA lpdm );
146 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
147 LPSTR lpszDevice, LPSTR lpszPort,
148 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
149 DWORD fwMode );
151 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
152 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
153 'c','o','n','t','r','o','l','\\',
154 'P','r','i','n','t','\\',
155 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
156 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
158 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
159 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
160 'C','o','n','t','r','o','l','\\',
161 'P','r','i','n','t','\\',
162 'M','o','n','i','t','o','r','s',0};
164 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
165 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
166 'C','o','n','t','r','o','l','\\',
167 'P','r','i','n','t','\\',
168 'P','r','i','n','t','e','r','s',0};
170 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
172 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
173 'M','i','c','r','o','s','o','f','t','\\',
174 'W','i','n','d','o','w','s',' ','N','T','\\',
175 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
176 'W','i','n','d','o','w','s',0};
178 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
179 'M','i','c','r','o','s','o','f','t','\\',
180 'W','i','n','d','o','w','s',' ','N','T','\\',
181 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
182 'D','e','v','i','c','e','s',0};
184 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
185 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
186 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
187 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
188 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
189 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
190 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
192 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
193 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
195 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
196 'i','o','n',' ','F','i','l','e',0};
197 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
198 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
199 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
200 'M','o','d','e',0};
201 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
202 'i','l','e','s',0};
203 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
204 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
205 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
206 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
207 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
208 static const WCHAR NameW[] = {'N','a','m','e',0};
209 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
210 static const WCHAR PortW[] = {'P','o','r','t',0};
211 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
212 's','s','o','r',0};
213 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
214 'v','e','r',0};
215 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
216 'v','e','r','D','a','t','a',0};
217 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
218 'i','l','e',0};
219 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
220 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
221 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
222 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
223 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
224 static const WCHAR emptyStringW[] = {0};
226 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
228 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
229 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
230 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
232 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
233 'D','o','c','u','m','e','n','t',0};
235 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
236 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
237 DWORD Level, LPBYTE pDriverInfo,
238 DWORD cbBuf, LPDWORD pcbNeeded,
239 BOOL unicode);
240 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey);
241 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey);
243 /******************************************************************
244 * validate the user-supplied printing-environment [internal]
246 * PARAMS
247 * env [I] PTR to Environment-String or NULL
249 * RETURNS
250 * Failure: NULL
251 * Success: PTR to printenv_t
253 * NOTES
254 * An empty string is handled the same way as NULL.
255 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
259 static const printenv_t * validate_envW(LPCWSTR env)
261 static const printenv_t env_x86 = {envname_x86W, subdir_x86W,
262 3, Version3_RegPathW, Version3_SubdirW};
263 static const printenv_t env_win40 = {envname_win40W, subdir_win40W,
264 0, emptyStringW, emptyStringW};
265 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
267 const printenv_t *result = NULL;
268 unsigned int i;
270 TRACE("testing %s\n", debugstr_w(env));
271 if (env && env[0])
273 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
275 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
277 result = all_printenv[i];
278 break;
282 if (result == NULL) {
283 FIXME("unsupported Environment: %s\n", debugstr_w(env));
284 SetLastError(ERROR_INVALID_ENVIRONMENT);
286 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
288 else
290 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
292 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
294 return result;
298 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
299 if passed a NULL string. This returns NULLs to the result.
301 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
303 if ( (src) )
305 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
306 return usBufferPtr->Buffer;
308 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
309 return NULL;
312 static LPWSTR strdupW(LPCWSTR p)
314 LPWSTR ret;
315 DWORD len;
317 if(!p) return NULL;
318 len = (strlenW(p) + 1) * sizeof(WCHAR);
319 ret = HeapAlloc(GetProcessHeap(), 0, len);
320 memcpy(ret, p, len);
321 return ret;
324 static void
325 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
326 char qbuf[200];
328 /* If forcing, or no profile string entry for device yet, set the entry
330 * The always change entry if not WINEPS yet is discussable.
332 if (force ||
333 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
334 !strcmp(qbuf,"*") ||
335 !strstr(qbuf,"WINEPS.DRV")
337 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
338 HKEY hkey;
340 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
341 WriteProfileStringA("windows","device",buf);
342 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
343 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
344 RegCloseKey(hkey);
346 HeapFree(GetProcessHeap(),0,buf);
350 #ifdef HAVE_CUPS_CUPS_H
351 static typeof(cupsGetDests) *pcupsGetDests;
352 static typeof(cupsGetPPD) *pcupsGetPPD;
353 static typeof(cupsPrintFile) *pcupsPrintFile;
354 static void *cupshandle;
356 static BOOL CUPS_LoadPrinters(void)
358 int i, nrofdests;
359 BOOL hadprinter = FALSE;
360 cups_dest_t *dests;
361 PRINTER_INFO_2A pinfo2a;
362 char *port,*devline;
363 HKEY hkeyPrinter, hkeyPrinters, hkey;
365 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
366 if (!cupshandle)
367 return FALSE;
368 TRACE("loaded %s\n", SONAME_LIBCUPS);
370 #define DYNCUPS(x) \
371 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
372 if (!p##x) return FALSE;
374 DYNCUPS(cupsGetPPD);
375 DYNCUPS(cupsGetDests);
376 DYNCUPS(cupsPrintFile);
377 #undef DYNCUPS
379 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
380 ERROR_SUCCESS) {
381 ERR("Can't create Printers key\n");
382 return FALSE;
385 nrofdests = pcupsGetDests(&dests);
386 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
387 for (i=0;i<nrofdests;i++) {
388 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
389 sprintf(port,"LPR:%s",dests[i].name);
390 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
391 sprintf(devline,"WINEPS.DRV,%s",port);
392 WriteProfileStringA("devices",dests[i].name,devline);
393 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
394 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
395 RegCloseKey(hkey);
397 HeapFree(GetProcessHeap(),0,devline);
399 TRACE("Printer %d: %s\n", i, dests[i].name);
400 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
401 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
402 and continue */
403 TRACE("Printer already exists\n");
404 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
405 RegCloseKey(hkeyPrinter);
406 } else {
407 static CHAR data_type[] = "RAW",
408 print_proc[] = "WinPrint",
409 driver_name[] = "PS Driver",
410 comment[] = "WINEPS Printer using CUPS",
411 location[] = "<physical location of printer>",
412 params[] = "<parameters?>",
413 share_name[] = "<share name?>",
414 sep_file[] = "<sep file?>";
416 memset(&pinfo2a,0,sizeof(pinfo2a));
417 pinfo2a.pPrinterName = dests[i].name;
418 pinfo2a.pDatatype = data_type;
419 pinfo2a.pPrintProcessor = print_proc;
420 pinfo2a.pDriverName = driver_name;
421 pinfo2a.pComment = comment;
422 pinfo2a.pLocation = location;
423 pinfo2a.pPortName = port;
424 pinfo2a.pParameters = params;
425 pinfo2a.pShareName = share_name;
426 pinfo2a.pSepFile = sep_file;
428 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
429 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
430 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",dests[i].name,GetLastError());
433 HeapFree(GetProcessHeap(),0,port);
435 hadprinter = TRUE;
436 if (dests[i].is_default)
437 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
439 RegCloseKey(hkeyPrinters);
440 return hadprinter;
442 #endif
444 static BOOL
445 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
446 PRINTER_INFO_2A pinfo2a;
447 char *e,*s,*name,*prettyname,*devname;
448 BOOL ret = FALSE, set_default = FALSE;
449 char *port,*devline,*env_default;
450 HKEY hkeyPrinter, hkeyPrinters, hkey;
452 while (isspace(*pent)) pent++;
453 s = strchr(pent,':');
454 if(s) *s='\0';
455 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
456 strcpy(name,pent);
457 if(s) {
458 *s=':';
459 pent = s;
460 } else
461 pent = "";
463 TRACE("name=%s entry=%s\n",name, pent);
465 if(ispunct(*name)) { /* a tc entry, not a real printer */
466 TRACE("skipping tc entry\n");
467 goto end;
470 if(strstr(pent,":server")) { /* server only version so skip */
471 TRACE("skipping server entry\n");
472 goto end;
475 /* Determine whether this is a postscript printer. */
477 ret = TRUE;
478 env_default = getenv("PRINTER");
479 prettyname = name;
480 /* Get longest name, usually the one at the right for later display. */
481 while((s=strchr(prettyname,'|'))) {
482 *s = '\0';
483 e = s;
484 while(isspace(*--e)) *e = '\0';
485 TRACE("\t%s\n", debugstr_a(prettyname));
486 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
487 for(prettyname = s+1; isspace(*prettyname); prettyname++)
490 e = prettyname + strlen(prettyname);
491 while(isspace(*--e)) *e = '\0';
492 TRACE("\t%s\n", debugstr_a(prettyname));
493 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
495 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
496 * if it is too long, we use it as comment below. */
497 devname = prettyname;
498 if (strlen(devname)>=CCHDEVICENAME-1)
499 devname = name;
500 if (strlen(devname)>=CCHDEVICENAME-1) {
501 ret = FALSE;
502 goto end;
505 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
506 sprintf(port,"LPR:%s",name);
508 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
509 sprintf(devline,"WINEPS.DRV,%s",port);
510 WriteProfileStringA("devices",devname,devline);
511 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
512 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
513 RegCloseKey(hkey);
515 HeapFree(GetProcessHeap(),0,devline);
517 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
518 ERROR_SUCCESS) {
519 ERR("Can't create Printers key\n");
520 ret = FALSE;
521 goto end;
523 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
524 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
525 and continue */
526 TRACE("Printer already exists\n");
527 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
528 RegCloseKey(hkeyPrinter);
529 } else {
530 static CHAR data_type[] = "RAW",
531 print_proc[] = "WinPrint",
532 driver_name[] = "PS Driver",
533 comment[] = "WINEPS Printer using LPR",
534 params[] = "<parameters?>",
535 share_name[] = "<share name?>",
536 sep_file[] = "<sep file?>";
538 memset(&pinfo2a,0,sizeof(pinfo2a));
539 pinfo2a.pPrinterName = devname;
540 pinfo2a.pDatatype = data_type;
541 pinfo2a.pPrintProcessor = print_proc;
542 pinfo2a.pDriverName = driver_name;
543 pinfo2a.pComment = comment;
544 pinfo2a.pLocation = prettyname;
545 pinfo2a.pPortName = port;
546 pinfo2a.pParameters = params;
547 pinfo2a.pShareName = share_name;
548 pinfo2a.pSepFile = sep_file;
550 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
551 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
552 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
555 RegCloseKey(hkeyPrinters);
557 if (isfirst || set_default)
558 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
560 HeapFree(GetProcessHeap(), 0, port);
561 end:
562 HeapFree(GetProcessHeap(), 0, name);
563 return ret;
566 static BOOL
567 PRINTCAP_LoadPrinters(void) {
568 BOOL hadprinter = FALSE;
569 char buf[200];
570 FILE *f;
571 char *pent = NULL;
572 BOOL had_bash = FALSE;
574 f = fopen("/etc/printcap","r");
575 if (!f)
576 return FALSE;
578 while(fgets(buf,sizeof(buf),f)) {
579 char *start, *end;
581 end=strchr(buf,'\n');
582 if (end) *end='\0';
584 start = buf;
585 while(isspace(*start)) start++;
586 if(*start == '#' || *start == '\0')
587 continue;
589 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
590 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
591 HeapFree(GetProcessHeap(),0,pent);
592 pent = NULL;
595 if (end && *--end == '\\') {
596 *end = '\0';
597 had_bash = TRUE;
598 } else
599 had_bash = FALSE;
601 if (pent) {
602 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
603 strcat(pent,start);
604 } else {
605 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
606 strcpy(pent,start);
610 if(pent) {
611 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
612 HeapFree(GetProcessHeap(),0,pent);
614 fclose(f);
615 return hadprinter;
618 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
620 if (value)
621 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
622 lstrlenW(value) * sizeof(WCHAR));
623 else
624 return ERROR_FILE_NOT_FOUND;
627 void WINSPOOL_LoadSystemPrinters(void)
629 HKEY hkey, hkeyPrinters;
630 DRIVER_INFO_3A di3a;
631 HANDLE hprn;
632 DWORD needed, num, i;
633 WCHAR PrinterName[256];
634 BOOL done = FALSE;
635 static CHAR name[] = "PS Driver",
636 driver_path[] = "wineps16",
637 data_file[] = "<datafile?>",
638 config_file[] = "wineps16",
639 help_file[] = "<helpfile?>",
640 dep_file[] = "<dependend files?>",
641 monitor_name[] = "<monitor name?>",
642 default_data_type[] = "RAW";
644 di3a.cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
645 di3a.pName = name;
646 di3a.pEnvironment = NULL; /* NULL means auto */
647 di3a.pDriverPath = driver_path;
648 di3a.pDataFile = data_file;
649 di3a.pConfigFile = config_file;
650 di3a.pHelpFile = help_file;
651 di3a.pDependentFiles = dep_file;
652 di3a.pMonitorName = monitor_name;
653 di3a.pDefaultDataType = default_data_type;
655 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
656 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
657 return;
660 /* This ensures that all printer entries have a valid Name value. If causes
661 problems later if they don't. If one is found to be missed we create one
662 and set it equal to the name of the key */
663 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
664 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
665 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
666 for(i = 0; i < num; i++) {
667 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
668 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
669 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
670 set_reg_szW(hkey, NameW, PrinterName);
672 RegCloseKey(hkey);
677 RegCloseKey(hkeyPrinters);
680 /* We want to avoid calling AddPrinter on printers as much as
681 possible, because on cups printers this will (eventually) lead
682 to a call to cupsGetPPD which takes forever, even with non-cups
683 printers AddPrinter takes a while. So we'll tag all printers that
684 were automatically added last time around, if they still exist
685 we'll leave them be otherwise we'll delete them. */
686 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
687 if(needed) {
688 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
689 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
690 for(i = 0; i < num; i++) {
691 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
692 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
693 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
694 DWORD dw = 1;
695 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
696 RegCloseKey(hkey);
698 ClosePrinter(hprn);
703 HeapFree(GetProcessHeap(), 0, pi);
707 #ifdef HAVE_CUPS_CUPS_H
708 done = CUPS_LoadPrinters();
709 #endif
711 if(!done) { /* If we have any CUPS based printers, skip looking for printcap printers */
712 /* Check for [ppd] section in config file before parsing /etc/printcap */
713 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
714 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Printing\\PPD Files",
715 &hkey) == ERROR_SUCCESS) {
716 RegCloseKey(hkey);
717 PRINTCAP_LoadPrinters();
721 /* Now enumerate the list again and delete any printers that a still tagged */
722 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
723 if(needed) {
724 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
725 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
726 for(i = 0; i < num; i++) {
727 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
728 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
729 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
730 DWORD dw, type, size = sizeof(dw);
731 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
732 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
733 DeletePrinter(hprn);
735 RegCloseKey(hkey);
737 ClosePrinter(hprn);
742 HeapFree(GetProcessHeap(), 0, pi);
745 return;
749 /*****************************************************************************
750 * enumerate the local monitors (INTERNAL)
752 * returns the needed size (in bytes) for pMonitors
753 * and *lpreturned is set to number of entries returned in pMonitors
756 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
758 HKEY hroot = NULL;
759 HKEY hentry = NULL;
760 LPWSTR ptr;
761 LPMONITOR_INFO_2W mi;
762 WCHAR buffer[MAX_PATH];
763 WCHAR dllname[MAX_PATH];
764 DWORD dllsize;
765 DWORD len;
766 DWORD index = 0;
767 DWORD needed = 0;
768 DWORD numentries;
769 DWORD entrysize;
771 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
773 numentries = *lpreturned; /* this is 0, when we scan the registry */
774 len = entrysize * numentries;
775 ptr = (LPWSTR) &pMonitors[len];
777 numentries = 0;
778 len = sizeof(buffer);
779 buffer[0] = '\0';
781 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
782 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
783 /* Scan all Monitor-Registry-Keys */
784 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
785 TRACE("Monitor_%ld: %s\n", numentries, debugstr_w(buffer));
786 dllsize = sizeof(dllname);
787 dllname[0] = '\0';
789 /* The Monitor must have a Driver-DLL */
790 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
791 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
792 /* We found a valid DLL for this Monitor. */
793 TRACE("using Driver: %s\n", debugstr_w(dllname));
795 RegCloseKey(hentry);
798 /* Windows returns only Port-Monitors here, but to simplify our code,
799 we do no filtering for Language-Monitors */
800 if (dllname[0]) {
801 numentries++;
802 needed += entrysize;
803 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
804 if (level > 1) {
805 /* we install and return only monitors for "Windows NT x86" */
806 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
807 needed += dllsize;
810 /* required size is calculated. Now fill the user-buffer */
811 if (pMonitors && (cbBuf >= needed)){
812 mi = (LPMONITOR_INFO_2W) pMonitors;
813 pMonitors += entrysize;
815 TRACE("%p: writing MONITOR_INFO_%ldW #%ld\n", mi, level, numentries);
816 mi->pName = ptr;
817 lstrcpyW(ptr, buffer); /* Name of the Monitor */
818 ptr += (len+1); /* len is lstrlenW(monitorname) */
819 if (level > 1) {
820 mi->pEnvironment = ptr;
821 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
822 ptr += (lstrlenW(envname_x86W)+1);
824 mi->pDLLName = ptr;
825 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
826 ptr += (dllsize / sizeof(WCHAR));
830 index++;
831 len = sizeof(buffer);
832 buffer[0] = '\0';
834 RegCloseKey(hroot);
836 *lpreturned = numentries;
837 TRACE("need %ld byte for %ld entries\n", needed, numentries);
838 return needed;
841 /******************************************************************
842 * monitor_unload [internal]
844 * release a printmonitor and unload it from memory, when needed
847 static void monitor_unload(monitor_t * pm)
849 TRACE("%p (refcount: %ld) %s\n", pm, pm->refcount, debugstr_w(pm->name));
851 EnterCriticalSection(&monitor_handles_cs);
853 if (pm->refcount) pm->refcount--;
855 if (pm->refcount == 0) {
856 list_remove(&pm->entry);
857 FreeLibrary(pm->hdll);
858 HeapFree(GetProcessHeap(), 0, pm->name);
859 HeapFree(GetProcessHeap(), 0, pm->dllname);
860 HeapFree(GetProcessHeap(), 0, pm);
862 LeaveCriticalSection(&monitor_handles_cs);
865 /******************************************************************
866 * monitor_load [internal]
868 * load a printmonitor, get the dllname from the registry, when needed
869 * initialize the monitor and dump found function-pointers
871 * On failure, SetLastError() is called and NULL is returned
874 static monitor_t * monitor_load(LPWSTR name, LPWSTR dllname)
876 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
877 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
878 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
879 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
880 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
882 monitor_t * pm = NULL;
883 monitor_t * cursor;
884 LPWSTR regroot = NULL;
885 LPWSTR driver = dllname;
887 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
888 /* Is the Monitor already loaded? */
889 EnterCriticalSection(&monitor_handles_cs);
891 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
893 if (lstrcmpW(name, cursor->name) == 0) {
894 pm = cursor;
895 break;
899 if (pm == NULL) {
900 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
901 if (pm == NULL) goto cleanup;
902 list_add_tail(&monitor_handles, &pm->entry);
904 pm->refcount++;
906 if (pm->name == NULL) {
907 /* Load the monitor */
908 LPMONITOREX pmonitorEx;
909 DWORD len;
911 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
912 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
914 if (regroot) {
915 lstrcpyW(regroot, MonitorsW);
916 lstrcatW(regroot, name);
917 /* Get the Driver from the Registry */
920 pm->name = strdupW(name);
921 pm->dllname = strdupW(driver);
923 if (!regroot || !pm->name || !pm->dllname) {
924 monitor_unload(pm);
925 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
926 pm = NULL;
927 goto cleanup;
930 pm->hdll = LoadLibraryW(driver);
931 TRACE("%p: LoadLibrary(%s) => %ld\n", pm->hdll, debugstr_w(driver), GetLastError());
933 if (pm->hdll == NULL) {
934 monitor_unload(pm);
935 SetLastError(ERROR_MOD_NOT_FOUND);
936 pm = NULL;
937 goto cleanup;
940 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
941 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
942 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
943 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
944 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
947 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
948 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
949 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
950 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
951 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
953 if (pInitializePrintMonitorUI != NULL) {
954 pm->monitorUI = pInitializePrintMonitorUI();
955 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
956 if (pm->monitorUI) {
957 TRACE( "0x%08lx: dwMonitorSize (%ld) => %ld Functions\n",
958 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize,
959 (pm->monitorUI->dwMonitorUISize - sizeof(DWORD) ) / sizeof(VOID *));
964 if (pInitializePrintMonitor != NULL) {
965 pmonitorEx = pInitializePrintMonitor(regroot);
966 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
967 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
969 if (pmonitorEx) {
970 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
971 pm->monitor = &(pmonitorEx->Monitor);
975 if (pm->monitor) {
976 TRACE( "0x%08lx: dwMonitorSize (%ld) => %ld Functions\n",
977 pm->dwMonitorSize, pm->dwMonitorSize,
978 (pm->dwMonitorSize) / sizeof(VOID *) );
982 if (!pm->monitor) {
983 if (pInitializePrintMonitor2 != NULL) {
984 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
986 if (pInitializeMonitorEx != NULL) {
987 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
989 if (pInitializeMonitor != NULL) {
990 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
993 if (!pm->monitor && !pm->monitorUI) {
994 monitor_unload(pm);
995 SetLastError(ERROR_PROC_NOT_FOUND);
996 pm = NULL;
999 cleanup:
1000 LeaveCriticalSection(&monitor_handles_cs);
1001 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
1002 HeapFree(GetProcessHeap(), 0, regroot);
1003 TRACE("=> %p\n", pm);
1004 return pm;
1007 /******************************************************************
1008 * get_opened_printer_entry
1009 * Get the first place empty in the opened printer table
1011 * ToDo:
1012 * - pDefault is ignored
1014 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1016 UINT_PTR handle = nb_printer_handles, i;
1017 jobqueue_t *queue = NULL;
1018 opened_printer_t *printer = NULL;
1020 EnterCriticalSection(&printer_handles_cs);
1022 for (i = 0; i < nb_printer_handles; i++)
1024 if (!printer_handles[i])
1026 if(handle == nb_printer_handles)
1027 handle = i;
1029 else
1031 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1032 queue = printer_handles[i]->queue;
1036 if (handle >= nb_printer_handles)
1038 opened_printer_t **new_array;
1039 if (printer_handles)
1040 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1041 (nb_printer_handles + 16) * sizeof(*new_array) );
1042 else
1043 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1044 (nb_printer_handles + 16) * sizeof(*new_array) );
1046 if (!new_array)
1048 handle = 0;
1049 goto end;
1051 printer_handles = new_array;
1052 nb_printer_handles += 16;
1055 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1057 handle = 0;
1058 goto end;
1061 if(name) {
1062 printer->name = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
1063 if (!printer->name) {
1064 handle = 0;
1065 goto end;
1067 strcpyW(printer->name, name);
1070 if(queue)
1071 printer->queue = queue;
1072 else
1074 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1075 if (!printer->queue) {
1076 handle = 0;
1077 goto end;
1079 list_init(&printer->queue->jobs);
1080 printer->queue->ref = 0;
1082 InterlockedIncrement(&printer->queue->ref);
1084 printer_handles[handle] = printer;
1085 handle++;
1086 end:
1087 LeaveCriticalSection(&printer_handles_cs);
1088 if (!handle && printer) {
1089 /* Something Failed: Free the Buffers */
1090 HeapFree(GetProcessHeap(), 0, printer->name);
1091 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1092 HeapFree(GetProcessHeap(), 0, printer);
1095 return (HANDLE)handle;
1098 /******************************************************************
1099 * get_opened_printer
1100 * Get the pointer to the opened printer referred by the handle
1102 static opened_printer_t *get_opened_printer(HANDLE hprn)
1104 UINT_PTR idx = (UINT_PTR)hprn;
1105 opened_printer_t *ret = NULL;
1107 EnterCriticalSection(&printer_handles_cs);
1109 if ((idx <= 0) || (idx > nb_printer_handles))
1110 goto end;
1112 ret = printer_handles[idx - 1];
1113 end:
1114 LeaveCriticalSection(&printer_handles_cs);
1115 return ret;
1118 /******************************************************************
1119 * get_opened_printer_name
1120 * Get the pointer to the opened printer name referred by the handle
1122 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1124 opened_printer_t *printer = get_opened_printer(hprn);
1125 if(!printer) return NULL;
1126 return printer->name;
1129 /******************************************************************
1130 * WINSPOOL_GetOpenedPrinterRegKey
1133 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1135 LPCWSTR name = get_opened_printer_name(hPrinter);
1136 DWORD ret;
1137 HKEY hkeyPrinters;
1139 if(!name) return ERROR_INVALID_HANDLE;
1141 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1142 ERROR_SUCCESS)
1143 return ret;
1145 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1147 ERR("Can't find opened printer %s in registry\n",
1148 debugstr_w(name));
1149 RegCloseKey(hkeyPrinters);
1150 return ERROR_INVALID_PRINTER_NAME; /* ? */
1152 RegCloseKey(hkeyPrinters);
1153 return ERROR_SUCCESS;
1156 /******************************************************************
1157 * get_job
1159 * Get the pointer to the specified job.
1160 * Should hold the printer_handles_cs before calling.
1162 static job_t *get_job(HANDLE hprn, DWORD JobId)
1164 opened_printer_t *printer = get_opened_printer(hprn);
1165 job_t *job;
1167 if(!printer) return NULL;
1168 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1170 if(job->job_id == JobId)
1171 return job;
1173 return NULL;
1176 /***********************************************************
1177 * DEVMODEcpyAtoW
1179 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1181 BOOL Formname;
1182 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1183 DWORD size;
1185 Formname = (dmA->dmSize > off_formname);
1186 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1187 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1188 dmW->dmDeviceName, CCHDEVICENAME);
1189 if(!Formname) {
1190 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1191 dmA->dmSize - CCHDEVICENAME);
1192 } else {
1193 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1194 off_formname - CCHDEVICENAME);
1195 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1196 dmW->dmFormName, CCHFORMNAME);
1197 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1198 (off_formname + CCHFORMNAME));
1200 dmW->dmSize = size;
1201 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1202 dmA->dmDriverExtra);
1203 return dmW;
1206 /***********************************************************
1207 * DEVMODEdupWtoA
1208 * Creates an ascii copy of supplied devmode on heap
1210 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
1212 LPDEVMODEA dmA;
1213 DWORD size;
1214 BOOL Formname;
1215 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
1217 if(!dmW) return NULL;
1218 Formname = (dmW->dmSize > off_formname);
1219 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
1220 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1221 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1222 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1223 if(!Formname) {
1224 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1225 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
1226 } else {
1227 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1228 off_formname - CCHDEVICENAME * sizeof(WCHAR));
1229 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1230 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1231 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
1232 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
1234 dmA->dmSize = size;
1235 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
1236 dmW->dmDriverExtra);
1237 return dmA;
1240 /***********************************************************
1241 * PRINTER_INFO_2AtoW
1242 * Creates a unicode copy of PRINTER_INFO_2A on heap
1244 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1246 LPPRINTER_INFO_2W piW;
1247 UNICODE_STRING usBuffer;
1249 if(!piA) return NULL;
1250 piW = HeapAlloc(heap, 0, sizeof(*piW));
1251 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1253 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1254 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1255 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1256 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1257 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1258 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1259 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1260 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1261 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1262 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1263 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1264 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1265 return piW;
1268 /***********************************************************
1269 * FREE_PRINTER_INFO_2W
1270 * Free PRINTER_INFO_2W and all strings
1272 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1274 if(!piW) return;
1276 HeapFree(heap,0,piW->pServerName);
1277 HeapFree(heap,0,piW->pPrinterName);
1278 HeapFree(heap,0,piW->pShareName);
1279 HeapFree(heap,0,piW->pPortName);
1280 HeapFree(heap,0,piW->pDriverName);
1281 HeapFree(heap,0,piW->pComment);
1282 HeapFree(heap,0,piW->pLocation);
1283 HeapFree(heap,0,piW->pDevMode);
1284 HeapFree(heap,0,piW->pSepFile);
1285 HeapFree(heap,0,piW->pPrintProcessor);
1286 HeapFree(heap,0,piW->pDatatype);
1287 HeapFree(heap,0,piW->pParameters);
1288 HeapFree(heap,0,piW);
1289 return;
1292 /******************************************************************
1293 * DeviceCapabilities [WINSPOOL.@]
1294 * DeviceCapabilitiesA [WINSPOOL.@]
1297 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1298 LPSTR pOutput, LPDEVMODEA lpdm)
1300 INT ret;
1302 if (!GDI_CallDeviceCapabilities16)
1304 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1305 (LPCSTR)104 );
1306 if (!GDI_CallDeviceCapabilities16) return -1;
1308 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1310 /* If DC_PAPERSIZE map POINT16s to POINTs */
1311 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1312 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1313 POINT *pt = (POINT *)pOutput;
1314 INT i;
1315 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1316 for(i = 0; i < ret; i++, pt++)
1318 pt->x = tmp[i].x;
1319 pt->y = tmp[i].y;
1321 HeapFree( GetProcessHeap(), 0, tmp );
1323 return ret;
1327 /*****************************************************************************
1328 * DeviceCapabilitiesW [WINSPOOL.@]
1330 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1333 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1334 WORD fwCapability, LPWSTR pOutput,
1335 const DEVMODEW *pDevMode)
1337 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
1338 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
1339 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
1340 INT ret;
1342 if(pOutput && (fwCapability == DC_BINNAMES ||
1343 fwCapability == DC_FILEDEPENDENCIES ||
1344 fwCapability == DC_PAPERNAMES)) {
1345 /* These need A -> W translation */
1346 INT size = 0, i;
1347 LPSTR pOutputA;
1348 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1349 dmA);
1350 if(ret == -1)
1351 return ret;
1352 switch(fwCapability) {
1353 case DC_BINNAMES:
1354 size = 24;
1355 break;
1356 case DC_PAPERNAMES:
1357 case DC_FILEDEPENDENCIES:
1358 size = 64;
1359 break;
1361 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1362 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1363 dmA);
1364 for(i = 0; i < ret; i++)
1365 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1366 pOutput + (i * size), size);
1367 HeapFree(GetProcessHeap(), 0, pOutputA);
1368 } else {
1369 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1370 (LPSTR)pOutput, dmA);
1372 HeapFree(GetProcessHeap(),0,pPortA);
1373 HeapFree(GetProcessHeap(),0,pDeviceA);
1374 HeapFree(GetProcessHeap(),0,dmA);
1375 return ret;
1378 /******************************************************************
1379 * DocumentPropertiesA [WINSPOOL.@]
1381 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1383 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1384 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1385 LPDEVMODEA pDevModeInput,DWORD fMode )
1387 LPSTR lpName = pDeviceName;
1388 static CHAR port[] = "LPT1:";
1389 LONG ret;
1391 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1392 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1395 if(!pDeviceName) {
1396 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1397 if(!lpNameW) {
1398 ERR("no name from hPrinter?\n");
1399 SetLastError(ERROR_INVALID_HANDLE);
1400 return -1;
1402 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
1405 if (!GDI_CallExtDeviceMode16)
1407 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1408 (LPCSTR)102 );
1409 if (!GDI_CallExtDeviceMode16) {
1410 ERR("No CallExtDeviceMode16?\n");
1411 return -1;
1414 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1415 pDevModeInput, NULL, fMode);
1417 if(!pDeviceName)
1418 HeapFree(GetProcessHeap(),0,lpName);
1419 return ret;
1423 /*****************************************************************************
1424 * DocumentPropertiesW (WINSPOOL.@)
1426 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1428 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1429 LPWSTR pDeviceName,
1430 LPDEVMODEW pDevModeOutput,
1431 LPDEVMODEW pDevModeInput, DWORD fMode)
1434 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
1435 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1436 LPDEVMODEA pDevModeOutputA = NULL;
1437 LONG ret;
1439 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1440 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1441 fMode);
1442 if(pDevModeOutput) {
1443 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1444 if(ret < 0) return ret;
1445 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1447 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1448 pDevModeInputA, fMode);
1449 if(pDevModeOutput) {
1450 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1451 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1453 if(fMode == 0 && ret > 0)
1454 ret += (CCHDEVICENAME + CCHFORMNAME);
1455 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1456 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1457 return ret;
1460 /******************************************************************
1461 * OpenPrinterA [WINSPOOL.@]
1463 * See OpenPrinterW.
1466 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1467 LPPRINTER_DEFAULTSA pDefault)
1469 UNICODE_STRING lpPrinterNameW;
1470 UNICODE_STRING usBuffer;
1471 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1472 PWSTR pwstrPrinterNameW;
1473 BOOL ret;
1475 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1477 if(pDefault) {
1478 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1479 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1480 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1481 pDefaultW = &DefaultW;
1483 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1484 if(pDefault) {
1485 RtlFreeUnicodeString(&usBuffer);
1486 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1488 RtlFreeUnicodeString(&lpPrinterNameW);
1489 return ret;
1492 /******************************************************************
1493 * OpenPrinterW [WINSPOOL.@]
1495 * Open a Printer / Printserver or a Printer-Object
1497 * PARAMS
1498 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1499 * phPrinter [O] The resulting Handle is stored here
1500 * pDefault [I] PTR to Default Printer Settings or NULL
1502 * RETURNS
1503 * Success: TRUE
1504 * Failure: FALSE
1506 * NOTES
1507 * lpPrinterName is one of:
1508 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1509 *| Printer: "PrinterName"
1510 *| Printer-Object: "PrinterName,Job xxx"
1511 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1512 *| XcvPort: "Servername,XcvPort PortName"
1514 * BUGS
1515 *| Printer-Object not supported
1516 *| XcvMonitor not supported
1517 *| XcvPort not supported
1518 *| pDefaults is ignored
1521 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1523 HKEY hkeyPrinters = NULL;
1524 HKEY hkeyPrinter = NULL;
1526 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1527 if (pDefault) {
1528 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08lx\n",
1529 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1532 if(lpPrinterName != NULL)
1534 /* Check any Printer exists */
1535 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1536 ERR("Can't create Printers key\n");
1537 SetLastError(ERROR_FILE_NOT_FOUND);
1538 return FALSE;
1540 if((lpPrinterName[0] == '\0') || /* explicitly exclude "" */
1541 (RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter) != ERROR_SUCCESS)) {
1543 WARN("Printer not found in Registry: '%s'\n", debugstr_w(lpPrinterName));
1544 RegCloseKey(hkeyPrinters);
1545 SetLastError(ERROR_INVALID_PRINTER_NAME);
1546 return FALSE;
1548 RegCloseKey(hkeyPrinter);
1549 RegCloseKey(hkeyPrinters);
1551 if(!phPrinter) {
1552 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1553 SetLastError(ERROR_INVALID_PARAMETER);
1554 return FALSE;
1557 /* Get the unique handle of the printer or Printserver */
1558 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1559 return (*phPrinter != 0);
1562 /******************************************************************
1563 * AddMonitorA [WINSPOOL.@]
1565 * See AddMonitorW.
1568 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1570 LPWSTR nameW = NULL;
1571 INT len;
1572 BOOL res;
1573 LPMONITOR_INFO_2A mi2a;
1574 MONITOR_INFO_2W mi2w;
1576 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1577 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1578 mi2a ? debugstr_a(mi2a->pName) : NULL,
1579 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
1580 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
1582 if (Level != 2) {
1583 SetLastError(ERROR_INVALID_LEVEL);
1584 return FALSE;
1587 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1588 if (mi2a == NULL) {
1589 return FALSE;
1592 if (pName) {
1593 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1594 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1595 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1598 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1599 if (mi2a->pName) {
1600 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1601 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1602 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1604 if (mi2a->pEnvironment) {
1605 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1606 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1607 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1609 if (mi2a->pDLLName) {
1610 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1611 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1612 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1615 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1617 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1618 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1619 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1621 HeapFree(GetProcessHeap(), 0, nameW);
1622 return (res);
1625 /******************************************************************************
1626 * AddMonitorW [WINSPOOL.@]
1628 * Install a Printmonitor
1630 * PARAMS
1631 * pName [I] Servername or NULL (local Computer)
1632 * Level [I] Structure-Level (Must be 2)
1633 * pMonitors [I] PTR to MONITOR_INFO_2
1635 * RETURNS
1636 * Success: TRUE
1637 * Failure: FALSE
1639 * NOTES
1640 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1643 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1645 monitor_t * pm = NULL;
1646 LPMONITOR_INFO_2W mi2w;
1647 HKEY hroot = NULL;
1648 HKEY hentry = NULL;
1649 DWORD disposition;
1650 BOOL res = FALSE;
1652 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1653 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1654 mi2w ? debugstr_w(mi2w->pName) : NULL,
1655 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
1656 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
1658 if (Level != 2) {
1659 SetLastError(ERROR_INVALID_LEVEL);
1660 return FALSE;
1663 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1664 if (mi2w == NULL) {
1665 return FALSE;
1668 if (pName && (pName[0])) {
1669 FIXME("for server %s not implemented\n", debugstr_w(pName));
1670 SetLastError(ERROR_ACCESS_DENIED);
1671 return FALSE;
1675 if (!mi2w->pName || (! mi2w->pName[0])) {
1676 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
1677 SetLastError(ERROR_INVALID_PARAMETER);
1678 return FALSE;
1680 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
1681 WARN("Environment %s requested (we support only %s)\n",
1682 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
1683 SetLastError(ERROR_INVALID_ENVIRONMENT);
1684 return FALSE;
1687 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
1688 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
1689 SetLastError(ERROR_INVALID_PARAMETER);
1690 return FALSE;
1693 /* Load and initialize the monitor. SetLastError() is called on failure */
1694 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
1695 return FALSE;
1697 monitor_unload(pm);
1699 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
1700 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
1701 return FALSE;
1704 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1705 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
1706 &disposition) == ERROR_SUCCESS) {
1708 /* Some installers set options for the port before calling AddMonitor.
1709 We query the "Driver" entry to verify that the monitor is installed,
1710 before we return an error.
1711 When a user installs two print monitors at the same time with the
1712 same name but with a different driver DLL and a task switch comes
1713 between RegQueryValueExW and RegSetValueExW, a race condition
1714 is possible but silently ignored. */
1716 DWORD namesize = 0;
1718 if ((disposition == REG_OPENED_EXISTING_KEY) &&
1719 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
1720 &namesize) == ERROR_SUCCESS)) {
1721 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
1722 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
1723 9x: ERROR_ALREADY_EXISTS (183) */
1724 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
1726 else
1728 INT len;
1729 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
1730 res = (RegSetValueExW(hentry, DriverW, 0,
1731 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
1733 RegCloseKey(hentry);
1736 RegCloseKey(hroot);
1737 return (res);
1740 /******************************************************************
1741 * DeletePrinterDriverA [WINSPOOL.@]
1744 BOOL WINAPI
1745 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1747 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1748 debugstr_a(pDriverName));
1749 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1750 return FALSE;
1753 /******************************************************************
1754 * DeletePrinterDriverW [WINSPOOL.@]
1757 BOOL WINAPI
1758 DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1760 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1761 debugstr_w(pDriverName));
1762 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1763 return FALSE;
1766 /******************************************************************
1767 * DeleteMonitorA [WINSPOOL.@]
1769 * See DeleteMonitorW.
1772 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1774 LPWSTR nameW = NULL;
1775 LPWSTR EnvironmentW = NULL;
1776 LPWSTR MonitorNameW = NULL;
1777 BOOL res;
1778 INT len;
1780 if (pName) {
1781 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1782 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1783 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1786 if (pEnvironment) {
1787 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
1788 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1789 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
1791 if (pMonitorName) {
1792 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
1793 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1794 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
1797 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
1799 HeapFree(GetProcessHeap(), 0, MonitorNameW);
1800 HeapFree(GetProcessHeap(), 0, EnvironmentW);
1801 HeapFree(GetProcessHeap(), 0, nameW);
1802 return (res);
1805 /******************************************************************
1806 * DeleteMonitorW [WINSPOOL.@]
1808 * Delete a specific Printmonitor from a Printing-Environment
1810 * PARAMS
1811 * pName [I] Servername or NULL (local Computer)
1812 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1813 * pMonitorName [I] Name of the Monitor, that should be deleted
1815 * RETURNS
1816 * Success: TRUE
1817 * Failure: FALSE
1819 * NOTES
1820 * pEnvironment is ignored in Windows for the local Computer.
1824 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1826 HKEY hroot = NULL;
1828 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1829 debugstr_w(pMonitorName));
1831 if (pName && (pName[0])) {
1832 FIXME("for server %s not implemented\n", debugstr_w(pName));
1833 SetLastError(ERROR_ACCESS_DENIED);
1834 return FALSE;
1837 /* pEnvironment is ignored in Windows for the local Computer */
1839 if (!pMonitorName || !pMonitorName[0]) {
1840 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
1841 SetLastError(ERROR_INVALID_PARAMETER);
1842 return FALSE;
1845 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
1846 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
1847 return FALSE;
1850 /* change this, when advapi32.dll/RegDeleteTree is implemented */
1851 if(WINSPOOL_SHDeleteKeyW(hroot, pMonitorName) == ERROR_SUCCESS) {
1852 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
1853 RegCloseKey(hroot);
1854 return TRUE;
1857 WARN("monitor %s does not exists\n", debugstr_w(pMonitorName));
1858 RegCloseKey(hroot);
1860 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1861 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
1862 return (FALSE);
1865 /******************************************************************
1866 * DeletePortA [WINSPOOL.@]
1868 * See DeletePortW.
1871 BOOL WINAPI
1872 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1874 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
1875 debugstr_a(pPortName));
1876 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1877 return FALSE;
1880 /******************************************************************
1881 * DeletePortW [WINSPOOL.@]
1883 * Delete a specific Port
1885 * PARAMS
1886 * pName [I] Servername or NULL (local Computer)
1887 * hWnd [I] Handle to parent Window for the Dialog-Box
1888 * pPortName [I] Name of the Port, that should be deleted
1890 * RETURNS
1891 * Success: TRUE
1892 * Failure: FALSE
1894 * BUGS
1895 * only a Stub
1898 BOOL WINAPI
1899 DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1901 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName),hWnd,
1902 debugstr_w(pPortName));
1903 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1904 return FALSE;
1907 /******************************************************************************
1908 * SetPrinterW [WINSPOOL.@]
1910 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
1912 FIXME("(%p, %ld, %p, %ld): stub\n", hPrinter, Level, pPrinter, Command);
1913 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1914 return FALSE;
1917 /******************************************************************************
1918 * WritePrinter [WINSPOOL.@]
1920 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
1922 opened_printer_t *printer;
1923 BOOL ret = FALSE;
1925 TRACE("(%p, %p, %ld, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
1927 EnterCriticalSection(&printer_handles_cs);
1928 printer = get_opened_printer(hPrinter);
1929 if(!printer)
1931 SetLastError(ERROR_INVALID_HANDLE);
1932 goto end;
1935 if(!printer->doc)
1937 SetLastError(ERROR_SPL_NO_STARTDOC);
1938 goto end;
1941 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
1942 end:
1943 LeaveCriticalSection(&printer_handles_cs);
1944 return ret;
1947 /*****************************************************************************
1948 * AddFormA [WINSPOOL.@]
1950 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1952 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1953 return 1;
1956 /*****************************************************************************
1957 * AddFormW [WINSPOOL.@]
1959 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1961 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1962 return 1;
1965 /*****************************************************************************
1966 * AddJobA [WINSPOOL.@]
1968 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1970 BOOL ret;
1971 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
1972 DWORD needed;
1974 if(Level != 1) {
1975 SetLastError(ERROR_INVALID_LEVEL);
1976 return FALSE;
1979 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
1981 if(ret) {
1982 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
1983 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
1984 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
1985 if(*pcbNeeded > cbBuf) {
1986 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1987 ret = FALSE;
1988 } else {
1989 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
1990 addjobA->JobId = addjobW->JobId;
1991 addjobA->Path = (char *)(addjobA + 1);
1992 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
1995 return ret;
1998 /*****************************************************************************
1999 * AddJobW [WINSPOOL.@]
2001 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2003 opened_printer_t *printer;
2004 job_t *job;
2005 BOOL ret = FALSE;
2006 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2007 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2008 WCHAR path[MAX_PATH], filename[MAX_PATH];
2009 DWORD len;
2010 ADDJOB_INFO_1W *addjob;
2012 TRACE("(%p,%ld,%p,%ld,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2014 EnterCriticalSection(&printer_handles_cs);
2016 printer = get_opened_printer(hPrinter);
2018 if(!printer) {
2019 SetLastError(ERROR_INVALID_HANDLE);
2020 goto end;
2023 if(Level != 1) {
2024 SetLastError(ERROR_INVALID_LEVEL);
2025 goto end;
2028 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2029 if(!job)
2030 goto end;
2032 job->job_id = InterlockedIncrement(&next_job_id);
2034 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2035 if(path[len - 1] != '\\')
2036 path[len++] = '\\';
2037 memcpy(path + len, spool_path, sizeof(spool_path));
2038 sprintfW(filename, fmtW, path, job->job_id);
2040 len = strlenW(filename);
2041 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2042 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2043 job->document_title = strdupW(default_doc_title);
2044 list_add_tail(&printer->queue->jobs, &job->entry);
2046 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2047 if(*pcbNeeded <= cbBuf) {
2048 addjob = (ADDJOB_INFO_1W*)pData;
2049 addjob->JobId = job->job_id;
2050 addjob->Path = (WCHAR *)(addjob + 1);
2051 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2052 ret = TRUE;
2053 } else
2054 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2056 end:
2057 LeaveCriticalSection(&printer_handles_cs);
2058 return ret;
2061 /*****************************************************************************
2062 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2064 * Return the PATH for the Print-Processors
2066 * See GetPrintProcessorDirectoryW.
2070 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2071 DWORD level, LPBYTE Info,
2072 DWORD cbBuf, LPDWORD pcbNeeded)
2074 LPWSTR serverW = NULL;
2075 LPWSTR envW = NULL;
2076 BOOL ret;
2077 INT len;
2079 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(server),
2080 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2083 if (server) {
2084 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2085 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2086 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2089 if (env) {
2090 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2091 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2092 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2095 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2096 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2098 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2099 cbBuf, pcbNeeded);
2101 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2102 cbBuf, NULL, NULL) > 0;
2105 TRACE(" required: 0x%lx/%ld\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2106 HeapFree(GetProcessHeap(), 0, envW);
2107 HeapFree(GetProcessHeap(), 0, serverW);
2108 return ret;
2111 /*****************************************************************************
2112 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2114 * Return the PATH for the Print-Processors
2116 * PARAMS
2117 * server [I] Servername (NT only) or NULL (local Computer)
2118 * env [I] Printing-Environment (see below) or NULL (Default)
2119 * level [I] Structure-Level (must be 1)
2120 * Info [O] PTR to Buffer that receives the Result
2121 * cbBuf [I] Size of Buffer at "Info"
2122 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2123 * required for the Buffer at "Info"
2125 * RETURNS
2126 * Success: TRUE and in pcbNeeded the Bytes used in Info
2127 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2128 * if cbBuf is too small
2130 * Native Values returned in Info on Success:
2131 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2132 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2133 *| win9x(Windows 4.0): "%winsysdir%"
2135 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2137 * BUGS
2138 * Only NULL or "" is supported for server
2141 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2142 DWORD level, LPBYTE Info,
2143 DWORD cbBuf, LPDWORD pcbNeeded)
2145 DWORD needed;
2146 const printenv_t * env_t;
2148 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(server),
2149 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2151 if(server != NULL && server[0]) {
2152 FIXME("server not supported: %s\n", debugstr_w(server));
2153 SetLastError(ERROR_INVALID_PARAMETER);
2154 return FALSE;
2157 env_t = validate_envW(env);
2158 if(!env_t) return FALSE; /* environment invalid or unsupported */
2160 if(level != 1) {
2161 WARN("(Level: %ld) is ignored in win9x\n", level);
2162 SetLastError(ERROR_INVALID_LEVEL);
2163 return FALSE;
2166 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2167 needed = GetSystemDirectoryW(NULL, 0);
2168 /* add the Size for the Subdirectories */
2169 needed += lstrlenW(spoolprtprocsW);
2170 needed += lstrlenW(env_t->subdir);
2171 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2173 if(pcbNeeded) *pcbNeeded = needed;
2174 TRACE ("required: 0x%lx/%ld\n", needed, needed);
2175 if (needed > cbBuf) {
2176 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2177 return FALSE;
2179 if(pcbNeeded == NULL) {
2180 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2181 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2182 SetLastError(RPC_X_NULL_REF_POINTER);
2183 return FALSE;
2185 if(Info == NULL) {
2186 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2187 SetLastError(RPC_X_NULL_REF_POINTER);
2188 return FALSE;
2191 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2192 /* add the Subdirectories */
2193 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2194 lstrcatW((LPWSTR) Info, env_t->subdir);
2195 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2196 return TRUE;
2199 /*****************************************************************************
2200 * WINSPOOL_OpenDriverReg [internal]
2202 * opens the registry for the printer drivers depending on the given input
2203 * variable pEnvironment
2205 * RETURNS:
2206 * the opened hkey on success
2207 * NULL on error
2209 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
2211 HKEY retval = NULL;
2212 LPWSTR buffer;
2213 const printenv_t * env;
2215 TRACE("(%s, %d)\n",
2216 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2218 if (!pEnvironment || unicode) {
2219 /* pEnvironment was NULL or an Unicode-String: use it direct */
2220 env = validate_envW(pEnvironment);
2222 else
2224 /* pEnvironment was an ANSI-String: convert to unicode first */
2225 LPWSTR buffer;
2226 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2227 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2228 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2229 env = validate_envW(buffer);
2230 HeapFree(GetProcessHeap(), 0, buffer);
2232 if (!env) return NULL;
2234 buffer = HeapAlloc( GetProcessHeap(), 0,
2235 (strlenW(DriversW) + strlenW(env->envname) +
2236 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2237 if(buffer) {
2238 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2239 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2240 HeapFree(GetProcessHeap(), 0, buffer);
2242 return retval;
2245 /*****************************************************************************
2246 * AddPrinterW [WINSPOOL.@]
2248 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2250 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2251 LPDEVMODEA dmA;
2252 LPDEVMODEW dmW;
2253 HANDLE retval;
2254 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2255 LONG size;
2257 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
2259 if(pName != NULL) {
2260 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2261 SetLastError(ERROR_INVALID_PARAMETER);
2262 return 0;
2264 if(Level != 2) {
2265 ERR("Level = %ld, unsupported!\n", Level);
2266 SetLastError(ERROR_INVALID_LEVEL);
2267 return 0;
2269 if(!pPrinter) {
2270 SetLastError(ERROR_INVALID_PARAMETER);
2271 return 0;
2273 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2274 ERROR_SUCCESS) {
2275 ERR("Can't create Printers key\n");
2276 return 0;
2278 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2279 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
2280 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2281 RegCloseKey(hkeyPrinter);
2282 RegCloseKey(hkeyPrinters);
2283 return 0;
2285 RegCloseKey(hkeyPrinter);
2287 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2288 if(!hkeyDrivers) {
2289 ERR("Can't create Drivers key\n");
2290 RegCloseKey(hkeyPrinters);
2291 return 0;
2293 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2294 ERROR_SUCCESS) {
2295 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2296 RegCloseKey(hkeyPrinters);
2297 RegCloseKey(hkeyDrivers);
2298 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2299 return 0;
2301 RegCloseKey(hkeyDriver);
2302 RegCloseKey(hkeyDrivers);
2304 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2305 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2306 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2307 RegCloseKey(hkeyPrinters);
2308 return 0;
2311 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2312 ERROR_SUCCESS) {
2313 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2314 SetLastError(ERROR_INVALID_PRINTER_NAME);
2315 RegCloseKey(hkeyPrinters);
2316 return 0;
2318 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
2319 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2320 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2322 /* See if we can load the driver. We may need the devmode structure anyway
2324 * FIXME:
2325 * Note that DocumentPropertiesW will briefly try to open the printer we
2326 * just create to find a DEVMODEA struct (it will use the WINEPS default
2327 * one in case it is not there, so we are ok).
2329 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2331 if(size < 0) {
2332 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
2333 size = sizeof(DEVMODEW);
2335 if(pi->pDevMode)
2336 dmW = pi->pDevMode;
2337 else
2339 dmW = HeapAlloc(GetProcessHeap(), 0, size);
2340 ZeroMemory(dmW,size);
2341 dmW->dmSize = size;
2342 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2344 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
2345 HeapFree(GetProcessHeap(),0,dmW);
2346 dmW=NULL;
2348 else
2350 /* set devmode to printer name */
2351 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2355 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2356 and we support these drivers. NT writes DEVMODEW so somehow
2357 we'll need to distinguish between these when we support NT
2358 drivers */
2359 if (dmW)
2361 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2362 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
2363 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2364 HeapFree(GetProcessHeap(), 0, dmA);
2365 if(!pi->pDevMode)
2366 HeapFree(GetProcessHeap(), 0, dmW);
2368 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2369 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2370 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2371 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2373 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2374 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2375 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2376 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
2377 (LPBYTE)&pi->Priority, sizeof(DWORD));
2378 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2379 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2380 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
2381 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2382 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
2383 (LPBYTE)&pi->Status, sizeof(DWORD));
2384 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
2385 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2387 RegCloseKey(hkeyPrinter);
2388 RegCloseKey(hkeyPrinters);
2389 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2390 ERR("OpenPrinter failing\n");
2391 return 0;
2393 return retval;
2396 /*****************************************************************************
2397 * AddPrinterA [WINSPOOL.@]
2399 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2401 UNICODE_STRING pNameW;
2402 PWSTR pwstrNameW;
2403 PRINTER_INFO_2W *piW;
2404 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2405 HANDLE ret;
2407 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2408 if(Level != 2) {
2409 ERR("Level = %ld, unsupported!\n", Level);
2410 SetLastError(ERROR_INVALID_LEVEL);
2411 return 0;
2413 pwstrNameW = asciitounicode(&pNameW,pName);
2414 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2416 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2418 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2419 RtlFreeUnicodeString(&pNameW);
2420 return ret;
2424 /*****************************************************************************
2425 * ClosePrinter [WINSPOOL.@]
2427 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2429 UINT_PTR i = (UINT_PTR)hPrinter;
2430 opened_printer_t *printer = NULL;
2431 BOOL ret = FALSE;
2433 TRACE("Handle %p\n", hPrinter);
2435 EnterCriticalSection(&printer_handles_cs);
2437 if ((i > 0) && (i <= nb_printer_handles))
2438 printer = printer_handles[i - 1];
2440 if(printer)
2442 struct list *cursor, *cursor2;
2444 if(printer->doc)
2445 EndDocPrinter(hPrinter);
2447 if(InterlockedDecrement(&printer->queue->ref) == 0)
2449 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2451 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2452 ScheduleJob(hPrinter, job->job_id);
2454 HeapFree(GetProcessHeap(), 0, printer->queue);
2456 HeapFree(GetProcessHeap(), 0, printer->name);
2457 HeapFree(GetProcessHeap(), 0, printer);
2458 printer_handles[i - 1] = NULL;
2459 ret = TRUE;
2461 LeaveCriticalSection(&printer_handles_cs);
2462 return ret;
2465 /*****************************************************************************
2466 * DeleteFormA [WINSPOOL.@]
2468 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2470 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2471 return 1;
2474 /*****************************************************************************
2475 * DeleteFormW [WINSPOOL.@]
2477 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2479 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2480 return 1;
2483 /*****************************************************************************
2484 * WINSPOOL_SHRegDeleteKey
2486 * Recursively delete subkeys.
2487 * Cut & paste from shlwapi.
2490 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
2492 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
2493 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2494 HKEY hSubKey = 0;
2496 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2497 if(!dwRet)
2499 /* Find how many subkeys there are */
2500 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
2501 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
2502 if(!dwRet)
2504 dwMaxSubkeyLen++;
2505 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
2506 /* Name too big: alloc a buffer for it */
2507 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
2509 if(!lpszName)
2510 dwRet = ERROR_NOT_ENOUGH_MEMORY;
2511 else
2513 /* Recursively delete all the subkeys */
2514 for(i = 0; i < dwKeyCount && !dwRet; i++)
2516 dwSize = dwMaxSubkeyLen;
2517 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
2518 if(!dwRet)
2519 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
2522 if (lpszName != szNameBuf)
2523 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
2527 RegCloseKey(hSubKey);
2528 if(!dwRet)
2529 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
2531 return dwRet;
2534 /*****************************************************************************
2535 * DeletePrinter [WINSPOOL.@]
2537 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2539 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2540 HKEY hkeyPrinters, hkey;
2542 if(!lpNameW) {
2543 SetLastError(ERROR_INVALID_HANDLE);
2544 return FALSE;
2546 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2547 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
2548 RegCloseKey(hkeyPrinters);
2550 WriteProfileStringW(devicesW, lpNameW, NULL);
2551 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2552 RegDeleteValueW(hkey, lpNameW);
2553 RegCloseKey(hkey);
2555 return TRUE;
2558 /*****************************************************************************
2559 * SetPrinterA [WINSPOOL.@]
2561 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2562 DWORD Command)
2564 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
2565 return FALSE;
2568 /*****************************************************************************
2569 * SetJobA [WINSPOOL.@]
2571 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2572 LPBYTE pJob, DWORD Command)
2574 BOOL ret;
2575 LPBYTE JobW;
2576 UNICODE_STRING usBuffer;
2578 TRACE("(%p, %ld, %ld, %p, %ld)\n",hPrinter, JobId, Level, pJob, Command);
2580 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2581 are all ignored by SetJob, so we don't bother copying them */
2582 switch(Level)
2584 case 0:
2585 JobW = NULL;
2586 break;
2587 case 1:
2589 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2590 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2592 JobW = (LPBYTE)info1W;
2593 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2594 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2595 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2596 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2597 info1W->Status = info1A->Status;
2598 info1W->Priority = info1A->Priority;
2599 info1W->Position = info1A->Position;
2600 info1W->PagesPrinted = info1A->PagesPrinted;
2601 break;
2603 case 2:
2605 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2606 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2608 JobW = (LPBYTE)info2W;
2609 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2610 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2611 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2612 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2613 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2614 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2615 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2616 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2617 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2618 info2W->Status = info2A->Status;
2619 info2W->Priority = info2A->Priority;
2620 info2W->Position = info2A->Position;
2621 info2W->StartTime = info2A->StartTime;
2622 info2W->UntilTime = info2A->UntilTime;
2623 info2W->PagesPrinted = info2A->PagesPrinted;
2624 break;
2626 case 3:
2627 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2628 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2629 break;
2630 default:
2631 SetLastError(ERROR_INVALID_LEVEL);
2632 return FALSE;
2635 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2637 switch(Level)
2639 case 1:
2641 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2642 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2643 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2644 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2645 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2646 break;
2648 case 2:
2650 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2651 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2652 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2653 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2654 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2655 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2656 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2657 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2658 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2659 break;
2662 HeapFree(GetProcessHeap(), 0, JobW);
2664 return ret;
2667 /*****************************************************************************
2668 * SetJobW [WINSPOOL.@]
2670 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2671 LPBYTE pJob, DWORD Command)
2673 BOOL ret = FALSE;
2674 job_t *job;
2676 TRACE("(%p, %ld, %ld, %p, %ld)\n", hPrinter, JobId, Level, pJob, Command);
2677 FIXME("Ignoring everything other than document title\n");
2679 EnterCriticalSection(&printer_handles_cs);
2680 job = get_job(hPrinter, JobId);
2681 if(!job)
2682 goto end;
2684 switch(Level)
2686 case 0:
2687 break;
2688 case 1:
2690 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2691 HeapFree(GetProcessHeap(), 0, job->document_title);
2692 job->document_title = strdupW(info1->pDocument);
2693 break;
2695 case 2:
2697 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2698 HeapFree(GetProcessHeap(), 0, job->document_title);
2699 job->document_title = strdupW(info2->pDocument);
2700 break;
2702 case 3:
2703 break;
2704 default:
2705 SetLastError(ERROR_INVALID_LEVEL);
2706 goto end;
2708 ret = TRUE;
2709 end:
2710 LeaveCriticalSection(&printer_handles_cs);
2711 return ret;
2714 /*****************************************************************************
2715 * EndDocPrinter [WINSPOOL.@]
2717 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2719 opened_printer_t *printer;
2720 BOOL ret = FALSE;
2721 TRACE("(%p)\n", hPrinter);
2723 EnterCriticalSection(&printer_handles_cs);
2725 printer = get_opened_printer(hPrinter);
2726 if(!printer)
2728 SetLastError(ERROR_INVALID_HANDLE);
2729 goto end;
2732 if(!printer->doc)
2734 SetLastError(ERROR_SPL_NO_STARTDOC);
2735 goto end;
2738 CloseHandle(printer->doc->hf);
2739 ScheduleJob(hPrinter, printer->doc->job_id);
2740 HeapFree(GetProcessHeap(), 0, printer->doc);
2741 printer->doc = NULL;
2742 ret = TRUE;
2743 end:
2744 LeaveCriticalSection(&printer_handles_cs);
2745 return ret;
2748 /*****************************************************************************
2749 * EndPagePrinter [WINSPOOL.@]
2751 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2753 FIXME("(%p): stub\n", hPrinter);
2754 return TRUE;
2757 /*****************************************************************************
2758 * StartDocPrinterA [WINSPOOL.@]
2760 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2762 UNICODE_STRING usBuffer;
2763 DOC_INFO_2W doc2W;
2764 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2765 DWORD ret;
2767 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2768 or one (DOC_INFO_3) extra DWORDs */
2770 switch(Level) {
2771 case 2:
2772 doc2W.JobId = doc2->JobId;
2773 /* fall through */
2774 case 3:
2775 doc2W.dwMode = doc2->dwMode;
2776 /* fall through */
2777 case 1:
2778 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2779 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2780 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2781 break;
2783 default:
2784 SetLastError(ERROR_INVALID_LEVEL);
2785 return FALSE;
2788 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2790 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2791 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2792 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2794 return ret;
2797 /*****************************************************************************
2798 * StartDocPrinterW [WINSPOOL.@]
2800 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2802 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2803 opened_printer_t *printer;
2804 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2805 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2806 JOB_INFO_1W job_info;
2807 DWORD needed, ret = 0;
2808 HANDLE hf;
2809 WCHAR *filename;
2811 TRACE("(hPrinter = %p, Level = %ld, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2812 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2813 debugstr_w(doc->pDatatype));
2815 if(Level < 1 || Level > 3)
2817 SetLastError(ERROR_INVALID_LEVEL);
2818 return 0;
2821 EnterCriticalSection(&printer_handles_cs);
2822 printer = get_opened_printer(hPrinter);
2823 if(!printer)
2825 SetLastError(ERROR_INVALID_HANDLE);
2826 goto end;
2829 if(printer->doc)
2831 SetLastError(ERROR_INVALID_PRINTER_STATE);
2832 goto end;
2835 /* Even if we're printing to a file we still add a print job, we'll
2836 just ignore the spool file name */
2838 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
2840 ERR("AddJob failed gle %08lx\n", GetLastError());
2841 goto end;
2844 if(doc->pOutputFile)
2845 filename = doc->pOutputFile;
2846 else
2847 filename = addjob->Path;
2849 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2850 if(hf == INVALID_HANDLE_VALUE)
2851 goto end;
2853 memset(&job_info, 0, sizeof(job_info));
2854 job_info.pDocument = doc->pDocName;
2855 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
2857 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
2858 printer->doc->hf = hf;
2859 ret = printer->doc->job_id = addjob->JobId;
2860 end:
2861 LeaveCriticalSection(&printer_handles_cs);
2863 return ret;
2866 /*****************************************************************************
2867 * StartPagePrinter [WINSPOOL.@]
2869 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
2871 FIXME("(%p): stub\n", hPrinter);
2872 return TRUE;
2875 /*****************************************************************************
2876 * GetFormA [WINSPOOL.@]
2878 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2879 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2881 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
2882 Level,pForm,cbBuf,pcbNeeded);
2883 return FALSE;
2886 /*****************************************************************************
2887 * GetFormW [WINSPOOL.@]
2889 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2890 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2892 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
2893 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
2894 return FALSE;
2897 /*****************************************************************************
2898 * SetFormA [WINSPOOL.@]
2900 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2901 LPBYTE pForm)
2903 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2904 return FALSE;
2907 /*****************************************************************************
2908 * SetFormW [WINSPOOL.@]
2910 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2911 LPBYTE pForm)
2913 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2914 return FALSE;
2917 /*****************************************************************************
2918 * ReadPrinter [WINSPOOL.@]
2920 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
2921 LPDWORD pNoBytesRead)
2923 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
2924 return FALSE;
2927 /*****************************************************************************
2928 * ResetPrinterA [WINSPOOL.@]
2930 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
2932 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2933 return FALSE;
2936 /*****************************************************************************
2937 * ResetPrinterW [WINSPOOL.@]
2939 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
2941 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2942 return FALSE;
2945 /*****************************************************************************
2946 * WINSPOOL_GetDWORDFromReg
2948 * Return DWORD associated with ValueName from hkey.
2950 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
2952 DWORD sz = sizeof(DWORD), type, value = 0;
2953 LONG ret;
2955 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
2957 if(ret != ERROR_SUCCESS) {
2958 WARN("Got ret = %ld on name %s\n", ret, ValueName);
2959 return 0;
2961 if(type != REG_DWORD) {
2962 ERR("Got type %ld\n", type);
2963 return 0;
2965 return value;
2968 /*****************************************************************************
2969 * WINSPOOL_GetStringFromReg
2971 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2972 * String is stored either as unicode or ascii.
2973 * Bit of a hack here to get the ValueName if we want ascii.
2975 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
2976 DWORD buflen, DWORD *needed,
2977 BOOL unicode)
2979 DWORD sz = buflen, type;
2980 LONG ret;
2982 if(unicode)
2983 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2984 else {
2985 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
2986 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
2987 HeapFree(GetProcessHeap(),0,ValueNameA);
2989 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
2990 WARN("Got ret = %ld\n", ret);
2991 *needed = 0;
2992 return FALSE;
2994 /* add space for terminating '\0' */
2995 sz += unicode ? sizeof(WCHAR) : 1;
2996 *needed = sz;
2998 if (ptr)
2999 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3001 return TRUE;
3004 /*****************************************************************************
3005 * WINSPOOL_GetDefaultDevMode
3007 * Get a default DevMode values for wineps.
3008 * FIXME - use ppd.
3011 static void WINSPOOL_GetDefaultDevMode(
3012 LPBYTE ptr,
3013 DWORD buflen, DWORD *needed,
3014 BOOL unicode)
3016 DEVMODEA dm;
3017 static const char szwps[] = "wineps.drv";
3019 /* fill default DEVMODE - should be read from ppd... */
3020 ZeroMemory( &dm, sizeof(dm) );
3021 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3022 dm.dmSpecVersion = DM_SPECVERSION;
3023 dm.dmDriverVersion = 1;
3024 dm.dmSize = sizeof(DEVMODEA);
3025 dm.dmDriverExtra = 0;
3026 dm.dmFields =
3027 DM_ORIENTATION | DM_PAPERSIZE |
3028 DM_PAPERLENGTH | DM_PAPERWIDTH |
3029 DM_SCALE |
3030 DM_COPIES |
3031 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3032 DM_YRESOLUTION | DM_TTOPTION;
3034 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3035 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3036 dm.u1.s1.dmPaperLength = 2970;
3037 dm.u1.s1.dmPaperWidth = 2100;
3039 dm.dmScale = 100;
3040 dm.dmCopies = 1;
3041 dm.dmDefaultSource = DMBIN_AUTO;
3042 dm.dmPrintQuality = DMRES_MEDIUM;
3043 /* dm.dmColor */
3044 /* dm.dmDuplex */
3045 dm.dmYResolution = 300; /* 300dpi */
3046 dm.dmTTOption = DMTT_BITMAP;
3047 /* dm.dmCollate */
3048 /* dm.dmFormName */
3049 /* dm.dmLogPixels */
3050 /* dm.dmBitsPerPel */
3051 /* dm.dmPelsWidth */
3052 /* dm.dmPelsHeight */
3053 /* dm.dmDisplayFlags */
3054 /* dm.dmDisplayFrequency */
3055 /* dm.dmICMMethod */
3056 /* dm.dmICMIntent */
3057 /* dm.dmMediaType */
3058 /* dm.dmDitherType */
3059 /* dm.dmReserved1 */
3060 /* dm.dmReserved2 */
3061 /* dm.dmPanningWidth */
3062 /* dm.dmPanningHeight */
3064 if(unicode) {
3065 if(buflen >= sizeof(DEVMODEW)) {
3066 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3067 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3068 HeapFree(GetProcessHeap(),0,pdmW);
3070 *needed = sizeof(DEVMODEW);
3072 else
3074 if(buflen >= sizeof(DEVMODEA)) {
3075 memcpy(ptr, &dm, sizeof(DEVMODEA));
3077 *needed = sizeof(DEVMODEA);
3081 /*****************************************************************************
3082 * WINSPOOL_GetDevModeFromReg
3084 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3085 * DevMode is stored either as unicode or ascii.
3087 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3088 LPBYTE ptr,
3089 DWORD buflen, DWORD *needed,
3090 BOOL unicode)
3092 DWORD sz = buflen, type;
3093 LONG ret;
3095 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3096 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3097 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3098 if (sz < sizeof(DEVMODEA))
3100 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
3101 return FALSE;
3103 /* ensures that dmSize is not erratically bogus if registry is invalid */
3104 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3105 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3106 if(unicode) {
3107 sz += (CCHDEVICENAME + CCHFORMNAME);
3108 if(buflen >= sz) {
3109 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3110 memcpy(ptr, dmW, sz);
3111 HeapFree(GetProcessHeap(),0,dmW);
3114 *needed = sz;
3115 return TRUE;
3118 /*********************************************************************
3119 * WINSPOOL_GetPrinter_2
3121 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3122 * The strings are either stored as unicode or ascii.
3124 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3125 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3126 BOOL unicode)
3128 DWORD size, left = cbBuf;
3129 BOOL space = (cbBuf > 0);
3130 LPBYTE ptr = buf;
3132 *pcbNeeded = 0;
3134 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3135 unicode)) {
3136 if(space && size <= left) {
3137 pi2->pPrinterName = (LPWSTR)ptr;
3138 ptr += size;
3139 left -= size;
3140 } else
3141 space = FALSE;
3142 *pcbNeeded += size;
3144 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3145 unicode)) {
3146 if(space && size <= left) {
3147 pi2->pShareName = (LPWSTR)ptr;
3148 ptr += size;
3149 left -= size;
3150 } else
3151 space = FALSE;
3152 *pcbNeeded += size;
3154 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3155 unicode)) {
3156 if(space && size <= left) {
3157 pi2->pPortName = (LPWSTR)ptr;
3158 ptr += size;
3159 left -= size;
3160 } else
3161 space = FALSE;
3162 *pcbNeeded += size;
3164 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3165 &size, unicode)) {
3166 if(space && size <= left) {
3167 pi2->pDriverName = (LPWSTR)ptr;
3168 ptr += size;
3169 left -= size;
3170 } else
3171 space = FALSE;
3172 *pcbNeeded += size;
3174 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3175 unicode)) {
3176 if(space && size <= left) {
3177 pi2->pComment = (LPWSTR)ptr;
3178 ptr += size;
3179 left -= size;
3180 } else
3181 space = FALSE;
3182 *pcbNeeded += size;
3184 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3185 unicode)) {
3186 if(space && size <= left) {
3187 pi2->pLocation = (LPWSTR)ptr;
3188 ptr += size;
3189 left -= size;
3190 } else
3191 space = FALSE;
3192 *pcbNeeded += size;
3194 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3195 &size, unicode)) {
3196 if(space && size <= left) {
3197 pi2->pDevMode = (LPDEVMODEW)ptr;
3198 ptr += size;
3199 left -= size;
3200 } else
3201 space = FALSE;
3202 *pcbNeeded += size;
3204 else
3206 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3207 if(space && size <= left) {
3208 pi2->pDevMode = (LPDEVMODEW)ptr;
3209 ptr += size;
3210 left -= size;
3211 } else
3212 space = FALSE;
3213 *pcbNeeded += size;
3215 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3216 &size, unicode)) {
3217 if(space && size <= left) {
3218 pi2->pSepFile = (LPWSTR)ptr;
3219 ptr += size;
3220 left -= size;
3221 } else
3222 space = FALSE;
3223 *pcbNeeded += size;
3225 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3226 &size, unicode)) {
3227 if(space && size <= left) {
3228 pi2->pPrintProcessor = (LPWSTR)ptr;
3229 ptr += size;
3230 left -= size;
3231 } else
3232 space = FALSE;
3233 *pcbNeeded += size;
3235 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3236 &size, unicode)) {
3237 if(space && size <= left) {
3238 pi2->pDatatype = (LPWSTR)ptr;
3239 ptr += size;
3240 left -= size;
3241 } else
3242 space = FALSE;
3243 *pcbNeeded += size;
3245 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3246 &size, unicode)) {
3247 if(space && size <= left) {
3248 pi2->pParameters = (LPWSTR)ptr;
3249 ptr += size;
3250 left -= size;
3251 } else
3252 space = FALSE;
3253 *pcbNeeded += size;
3255 if(pi2) {
3256 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3257 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3258 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3259 "Default Priority");
3260 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3261 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3264 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3265 memset(pi2, 0, sizeof(*pi2));
3267 return space;
3270 /*********************************************************************
3271 * WINSPOOL_GetPrinter_4
3273 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3275 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3276 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3277 BOOL unicode)
3279 DWORD size, left = cbBuf;
3280 BOOL space = (cbBuf > 0);
3281 LPBYTE ptr = buf;
3283 *pcbNeeded = 0;
3285 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3286 unicode)) {
3287 if(space && size <= left) {
3288 pi4->pPrinterName = (LPWSTR)ptr;
3289 ptr += size;
3290 left -= size;
3291 } else
3292 space = FALSE;
3293 *pcbNeeded += size;
3295 if(pi4) {
3296 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3299 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3300 memset(pi4, 0, sizeof(*pi4));
3302 return space;
3305 /*********************************************************************
3306 * WINSPOOL_GetPrinter_5
3308 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3310 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3311 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3312 BOOL unicode)
3314 DWORD size, left = cbBuf;
3315 BOOL space = (cbBuf > 0);
3316 LPBYTE ptr = buf;
3318 *pcbNeeded = 0;
3320 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3321 unicode)) {
3322 if(space && size <= left) {
3323 pi5->pPrinterName = (LPWSTR)ptr;
3324 ptr += size;
3325 left -= size;
3326 } else
3327 space = FALSE;
3328 *pcbNeeded += size;
3330 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3331 unicode)) {
3332 if(space && size <= left) {
3333 pi5->pPortName = (LPWSTR)ptr;
3334 ptr += size;
3335 left -= size;
3336 } else
3337 space = FALSE;
3338 *pcbNeeded += size;
3340 if(pi5) {
3341 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3342 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3343 "dnsTimeout");
3344 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3345 "txTimeout");
3348 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3349 memset(pi5, 0, sizeof(*pi5));
3351 return space;
3354 /*****************************************************************************
3355 * WINSPOOL_GetPrinter
3357 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3358 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3359 * just a collection of pointers to strings.
3361 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3362 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3364 LPCWSTR name;
3365 DWORD size, needed = 0;
3366 LPBYTE ptr = NULL;
3367 HKEY hkeyPrinter, hkeyPrinters;
3368 BOOL ret;
3370 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3372 if (!(name = get_opened_printer_name(hPrinter))) {
3373 SetLastError(ERROR_INVALID_HANDLE);
3374 return FALSE;
3377 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3378 ERROR_SUCCESS) {
3379 ERR("Can't create Printers key\n");
3380 return FALSE;
3382 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3384 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3385 RegCloseKey(hkeyPrinters);
3386 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3387 return FALSE;
3390 switch(Level) {
3391 case 2:
3393 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3395 size = sizeof(PRINTER_INFO_2W);
3396 if(size <= cbBuf) {
3397 ptr = pPrinter + size;
3398 cbBuf -= size;
3399 memset(pPrinter, 0, size);
3400 } else {
3401 pi2 = NULL;
3402 cbBuf = 0;
3404 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3405 unicode);
3406 needed += size;
3407 break;
3410 case 4:
3412 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3414 size = sizeof(PRINTER_INFO_4W);
3415 if(size <= cbBuf) {
3416 ptr = pPrinter + size;
3417 cbBuf -= size;
3418 memset(pPrinter, 0, size);
3419 } else {
3420 pi4 = NULL;
3421 cbBuf = 0;
3423 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
3424 unicode);
3425 needed += size;
3426 break;
3430 case 5:
3432 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3434 size = sizeof(PRINTER_INFO_5W);
3435 if(size <= cbBuf) {
3436 ptr = pPrinter + size;
3437 cbBuf -= size;
3438 memset(pPrinter, 0, size);
3439 } else {
3440 pi5 = NULL;
3441 cbBuf = 0;
3444 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
3445 unicode);
3446 needed += size;
3447 break;
3450 default:
3451 FIXME("Unimplemented level %ld\n", Level);
3452 SetLastError(ERROR_INVALID_LEVEL);
3453 RegCloseKey(hkeyPrinters);
3454 RegCloseKey(hkeyPrinter);
3455 return FALSE;
3458 RegCloseKey(hkeyPrinter);
3459 RegCloseKey(hkeyPrinters);
3461 TRACE("returning %d needed = %ld\n", ret, needed);
3462 if(pcbNeeded) *pcbNeeded = needed;
3463 if(!ret)
3464 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3465 return ret;
3468 /*****************************************************************************
3469 * GetPrinterW [WINSPOOL.@]
3471 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3472 DWORD cbBuf, LPDWORD pcbNeeded)
3474 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3475 TRUE);
3478 /*****************************************************************************
3479 * GetPrinterA [WINSPOOL.@]
3481 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3482 DWORD cbBuf, LPDWORD pcbNeeded)
3484 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3485 FALSE);
3488 /*****************************************************************************
3489 * WINSPOOL_EnumPrinters
3491 * Implementation of EnumPrintersA|W
3493 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
3494 DWORD dwLevel, LPBYTE lpbPrinters,
3495 DWORD cbBuf, LPDWORD lpdwNeeded,
3496 LPDWORD lpdwReturned, BOOL unicode)
3499 HKEY hkeyPrinters, hkeyPrinter;
3500 WCHAR PrinterName[255];
3501 DWORD needed = 0, number = 0;
3502 DWORD used, i, left;
3503 PBYTE pi, buf;
3505 if(lpbPrinters)
3506 memset(lpbPrinters, 0, cbBuf);
3507 if(lpdwReturned)
3508 *lpdwReturned = 0;
3509 if(lpdwNeeded)
3510 *lpdwNeeded = 0;
3512 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3513 if(dwType == PRINTER_ENUM_DEFAULT)
3514 return TRUE;
3516 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3517 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3518 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3519 if(!dwType) return TRUE;
3522 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3523 FIXME("dwType = %08lx\n", dwType);
3524 SetLastError(ERROR_INVALID_FLAGS);
3525 return FALSE;
3528 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3529 ERROR_SUCCESS) {
3530 ERR("Can't create Printers key\n");
3531 return FALSE;
3534 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3535 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3536 RegCloseKey(hkeyPrinters);
3537 ERR("Can't query Printers key\n");
3538 return FALSE;
3540 TRACE("Found %ld printers\n", number);
3542 switch(dwLevel) {
3543 case 1:
3544 RegCloseKey(hkeyPrinters);
3545 if (lpdwReturned)
3546 *lpdwReturned = number;
3547 return TRUE;
3549 case 2:
3550 used = number * sizeof(PRINTER_INFO_2W);
3551 break;
3552 case 4:
3553 used = number * sizeof(PRINTER_INFO_4W);
3554 break;
3555 case 5:
3556 used = number * sizeof(PRINTER_INFO_5W);
3557 break;
3559 default:
3560 SetLastError(ERROR_INVALID_LEVEL);
3561 RegCloseKey(hkeyPrinters);
3562 return FALSE;
3564 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3566 for(i = 0; i < number; i++) {
3567 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
3568 ERROR_SUCCESS) {
3569 ERR("Can't enum key number %ld\n", i);
3570 RegCloseKey(hkeyPrinters);
3571 return FALSE;
3573 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
3574 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3575 ERROR_SUCCESS) {
3576 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3577 RegCloseKey(hkeyPrinters);
3578 return FALSE;
3581 if(cbBuf > used) {
3582 buf = lpbPrinters + used;
3583 left = cbBuf - used;
3584 } else {
3585 buf = NULL;
3586 left = 0;
3589 switch(dwLevel) {
3590 case 2:
3591 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
3592 left, &needed, unicode);
3593 used += needed;
3594 if(pi) pi += sizeof(PRINTER_INFO_2W);
3595 break;
3596 case 4:
3597 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
3598 left, &needed, unicode);
3599 used += needed;
3600 if(pi) pi += sizeof(PRINTER_INFO_4W);
3601 break;
3602 case 5:
3603 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
3604 left, &needed, unicode);
3605 used += needed;
3606 if(pi) pi += sizeof(PRINTER_INFO_5W);
3607 break;
3608 default:
3609 ERR("Shouldn't be here!\n");
3610 RegCloseKey(hkeyPrinter);
3611 RegCloseKey(hkeyPrinters);
3612 return FALSE;
3614 RegCloseKey(hkeyPrinter);
3616 RegCloseKey(hkeyPrinters);
3618 if(lpdwNeeded)
3619 *lpdwNeeded = used;
3621 if(used > cbBuf) {
3622 if(lpbPrinters)
3623 memset(lpbPrinters, 0, cbBuf);
3624 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3625 return FALSE;
3627 if(lpdwReturned)
3628 *lpdwReturned = number;
3629 SetLastError(ERROR_SUCCESS);
3630 return TRUE;
3634 /******************************************************************
3635 * EnumPrintersW [WINSPOOL.@]
3637 * Enumerates the available printers, print servers and print
3638 * providers, depending on the specified flags, name and level.
3640 * RETURNS:
3642 * If level is set to 1:
3643 * Not implemented yet!
3644 * Returns TRUE with an empty list.
3646 * If level is set to 2:
3647 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3648 * Returns an array of PRINTER_INFO_2 data structures in the
3649 * lpbPrinters buffer. Note that according to MSDN also an
3650 * OpenPrinter should be performed on every remote printer.
3652 * If level is set to 4 (officially WinNT only):
3653 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3654 * Fast: Only the registry is queried to retrieve printer names,
3655 * no connection to the driver is made.
3656 * Returns an array of PRINTER_INFO_4 data structures in the
3657 * lpbPrinters buffer.
3659 * If level is set to 5 (officially WinNT4/Win9x only):
3660 * Fast: Only the registry is queried to retrieve printer names,
3661 * no connection to the driver is made.
3662 * Returns an array of PRINTER_INFO_5 data structures in the
3663 * lpbPrinters buffer.
3665 * If level set to 3 or 6+:
3666 * returns zero (failure!)
3668 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
3669 * for information.
3671 * BUGS:
3672 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
3673 * - Only levels 2, 4 and 5 are implemented at the moment.
3674 * - 16-bit printer drivers are not enumerated.
3675 * - Returned amount of bytes used/needed does not match the real Windoze
3676 * implementation (as in this implementation, all strings are part
3677 * of the buffer, whereas Win32 keeps them somewhere else)
3678 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
3680 * NOTE:
3681 * - In a regular Wine installation, no registry settings for printers
3682 * exist, which makes this function return an empty list.
3684 BOOL WINAPI EnumPrintersW(
3685 DWORD dwType, /* [in] Types of print objects to enumerate */
3686 LPWSTR lpszName, /* [in] name of objects to enumerate */
3687 DWORD dwLevel, /* [in] type of printer info structure */
3688 LPBYTE lpbPrinters, /* [out] buffer which receives info */
3689 DWORD cbBuf, /* [in] max size of buffer in bytes */
3690 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
3691 LPDWORD lpdwReturned /* [out] number of entries returned */
3694 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
3695 lpdwNeeded, lpdwReturned, TRUE);
3698 /******************************************************************
3699 * EnumPrintersA [WINSPOOL.@]
3702 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
3703 DWORD dwLevel, LPBYTE lpbPrinters,
3704 DWORD cbBuf, LPDWORD lpdwNeeded,
3705 LPDWORD lpdwReturned)
3707 BOOL ret;
3708 UNICODE_STRING lpszNameW;
3709 PWSTR pwstrNameW;
3711 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
3712 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
3713 lpdwNeeded, lpdwReturned, FALSE);
3714 RtlFreeUnicodeString(&lpszNameW);
3715 return ret;
3718 /*****************************************************************************
3719 * WINSPOOL_GetDriverInfoFromReg [internal]
3721 * Enters the information from the registry into the DRIVER_INFO struct
3723 * RETURNS
3724 * zero if the printer driver does not exist in the registry
3725 * (only if Level > 1) otherwise nonzero
3727 static BOOL WINSPOOL_GetDriverInfoFromReg(
3728 HKEY hkeyDrivers,
3729 LPWSTR DriverName,
3730 LPWSTR pEnvironment,
3731 DWORD Level,
3732 LPBYTE ptr, /* DRIVER_INFO */
3733 LPBYTE pDriverStrings, /* strings buffer */
3734 DWORD cbBuf, /* size of string buffer */
3735 LPDWORD pcbNeeded, /* space needed for str. */
3736 BOOL unicode) /* type of strings */
3738 DWORD size, tmp;
3739 HKEY hkeyDriver;
3740 LPBYTE strPtr = pDriverStrings;
3742 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
3743 debugstr_w(DriverName), debugstr_w(pEnvironment),
3744 Level, ptr, pDriverStrings, cbBuf, unicode);
3746 if(unicode) {
3747 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
3748 if (*pcbNeeded <= cbBuf)
3749 strcpyW((LPWSTR)strPtr, DriverName);
3750 } else {
3751 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
3752 NULL, NULL);
3753 if(*pcbNeeded <= cbBuf)
3754 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
3755 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
3757 if(Level == 1) {
3758 if(ptr)
3759 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
3760 return TRUE;
3761 } else {
3762 if(ptr)
3763 ((PDRIVER_INFO_2W) ptr)->pName = (LPWSTR) strPtr;
3764 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3767 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
3768 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
3769 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
3770 return FALSE;
3773 if(ptr)
3774 ((PDRIVER_INFO_2A) ptr)->cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
3776 if(!pEnvironment)
3777 pEnvironment = (LPWSTR)DefaultEnvironmentW;
3778 if(unicode)
3779 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
3780 else
3781 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
3782 NULL, NULL);
3783 *pcbNeeded += size;
3784 if(*pcbNeeded <= cbBuf) {
3785 if(unicode)
3786 strcpyW((LPWSTR)strPtr, pEnvironment);
3787 else
3788 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
3789 (LPSTR)strPtr, size, NULL, NULL);
3790 if(ptr)
3791 ((PDRIVER_INFO_2W) ptr)->pEnvironment = (LPWSTR)strPtr;
3792 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3795 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
3796 unicode)) {
3797 *pcbNeeded += size;
3798 if(*pcbNeeded <= cbBuf)
3799 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
3800 unicode);
3801 if(ptr)
3802 ((PDRIVER_INFO_2W) ptr)->pDriverPath = (LPWSTR)strPtr;
3803 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3806 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
3807 unicode)) {
3808 *pcbNeeded += size;
3809 if(*pcbNeeded <= cbBuf)
3810 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
3811 &tmp, unicode);
3812 if(ptr)
3813 ((PDRIVER_INFO_2W) ptr)->pDataFile = (LPWSTR)strPtr;
3814 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3817 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3818 0, &size, unicode)) {
3819 *pcbNeeded += size;
3820 if(*pcbNeeded <= cbBuf)
3821 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3822 size, &tmp, unicode);
3823 if(ptr)
3824 ((PDRIVER_INFO_2W) ptr)->pConfigFile = (LPWSTR)strPtr;
3825 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3828 if(Level == 2 ) {
3829 RegCloseKey(hkeyDriver);
3830 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3831 return TRUE;
3834 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
3835 unicode)) {
3836 *pcbNeeded += size;
3837 if(*pcbNeeded <= cbBuf)
3838 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
3839 size, &tmp, unicode);
3840 if(ptr)
3841 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
3842 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3845 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
3846 &size, unicode)) {
3847 *pcbNeeded += size;
3848 if(*pcbNeeded <= cbBuf)
3849 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
3850 size, &tmp, unicode);
3851 if(ptr)
3852 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
3853 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3856 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
3857 unicode)) {
3858 *pcbNeeded += size;
3859 if(*pcbNeeded <= cbBuf)
3860 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
3861 size, &tmp, unicode);
3862 if(ptr)
3863 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
3864 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3867 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
3868 unicode)) {
3869 *pcbNeeded += size;
3870 if(*pcbNeeded <= cbBuf)
3871 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
3872 size, &tmp, unicode);
3873 if(ptr)
3874 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
3875 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3878 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3879 RegCloseKey(hkeyDriver);
3880 return TRUE;
3883 /*****************************************************************************
3884 * WINSPOOL_GetPrinterDriver
3886 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
3887 DWORD Level, LPBYTE pDriverInfo,
3888 DWORD cbBuf, LPDWORD pcbNeeded,
3889 BOOL unicode)
3891 LPCWSTR name;
3892 WCHAR DriverName[100];
3893 DWORD ret, type, size, needed = 0;
3894 LPBYTE ptr = NULL;
3895 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
3897 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
3898 Level,pDriverInfo,cbBuf, pcbNeeded);
3900 ZeroMemory(pDriverInfo, cbBuf);
3902 if (!(name = get_opened_printer_name(hPrinter))) {
3903 SetLastError(ERROR_INVALID_HANDLE);
3904 return FALSE;
3906 if(Level < 1 || Level > 6) {
3907 SetLastError(ERROR_INVALID_LEVEL);
3908 return FALSE;
3910 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3911 ERROR_SUCCESS) {
3912 ERR("Can't create Printers key\n");
3913 return FALSE;
3915 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
3916 != ERROR_SUCCESS) {
3917 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3918 RegCloseKey(hkeyPrinters);
3919 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3920 return FALSE;
3922 size = sizeof(DriverName);
3923 DriverName[0] = 0;
3924 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
3925 (LPBYTE)DriverName, &size);
3926 RegCloseKey(hkeyPrinter);
3927 RegCloseKey(hkeyPrinters);
3928 if(ret != ERROR_SUCCESS) {
3929 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
3930 return FALSE;
3933 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
3934 if(!hkeyDrivers) {
3935 ERR("Can't create Drivers key\n");
3936 return FALSE;
3939 switch(Level) {
3940 case 1:
3941 size = sizeof(DRIVER_INFO_1W);
3942 break;
3943 case 2:
3944 size = sizeof(DRIVER_INFO_2W);
3945 break;
3946 case 3:
3947 size = sizeof(DRIVER_INFO_3W);
3948 break;
3949 case 4:
3950 size = sizeof(DRIVER_INFO_4W);
3951 break;
3952 case 5:
3953 size = sizeof(DRIVER_INFO_5W);
3954 break;
3955 case 6:
3956 size = sizeof(DRIVER_INFO_6W);
3957 break;
3958 default:
3959 ERR("Invalid level\n");
3960 return FALSE;
3963 if(size <= cbBuf)
3964 ptr = pDriverInfo + size;
3966 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
3967 pEnvironment, Level, pDriverInfo,
3968 (cbBuf < size) ? NULL : ptr,
3969 (cbBuf < size) ? 0 : cbBuf - size,
3970 &needed, unicode)) {
3971 RegCloseKey(hkeyDrivers);
3972 return FALSE;
3975 RegCloseKey(hkeyDrivers);
3977 if(pcbNeeded) *pcbNeeded = size + needed;
3978 TRACE("buffer space %ld required %ld\n", cbBuf, size + needed);
3979 if(cbBuf >= needed) return TRUE;
3980 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3981 return FALSE;
3984 /*****************************************************************************
3985 * GetPrinterDriverA [WINSPOOL.@]
3987 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
3988 DWORD Level, LPBYTE pDriverInfo,
3989 DWORD cbBuf, LPDWORD pcbNeeded)
3991 BOOL ret;
3992 UNICODE_STRING pEnvW;
3993 PWSTR pwstrEnvW;
3995 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
3996 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
3997 cbBuf, pcbNeeded, FALSE);
3998 RtlFreeUnicodeString(&pEnvW);
3999 return ret;
4001 /*****************************************************************************
4002 * GetPrinterDriverW [WINSPOOL.@]
4004 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4005 DWORD Level, LPBYTE pDriverInfo,
4006 DWORD cbBuf, LPDWORD pcbNeeded)
4008 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4009 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4012 /*****************************************************************************
4013 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4015 * Return the PATH for the Printer-Drivers (UNICODE)
4017 * PARAMS
4018 * pName [I] Servername (NT only) or NULL (local Computer)
4019 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4020 * Level [I] Structure-Level (must be 1)
4021 * pDriverDirectory [O] PTR to Buffer that receives the Result
4022 * cbBuf [I] Size of Buffer at pDriverDirectory
4023 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4024 * required for pDriverDirectory
4026 * RETURNS
4027 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4028 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4029 * if cbBuf is too small
4031 * Native Values returned in pDriverDirectory on Success:
4032 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4033 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4034 *| win9x(Windows 4.0): "%winsysdir%"
4036 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4038 * FIXME
4039 *- Only NULL or "" is supported for pName
4042 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4043 DWORD Level, LPBYTE pDriverDirectory,
4044 DWORD cbBuf, LPDWORD pcbNeeded)
4046 DWORD needed;
4047 const printenv_t * env;
4049 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
4050 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4051 if(pName != NULL && pName[0]) {
4052 FIXME("pName unsupported: %s\n", debugstr_w(pName));
4053 SetLastError(ERROR_INVALID_PARAMETER);
4054 return FALSE;
4057 env = validate_envW(pEnvironment);
4058 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
4060 if(Level != 1) {
4061 WARN("(Level: %ld) is ignored in win9x\n", Level);
4062 SetLastError(ERROR_INVALID_LEVEL);
4063 return FALSE;
4066 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
4067 needed = GetSystemDirectoryW(NULL, 0);
4068 /* add the Size for the Subdirectories */
4069 needed += lstrlenW(spooldriversW);
4070 needed += lstrlenW(env->subdir);
4071 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
4073 if(pcbNeeded)
4074 *pcbNeeded = needed;
4075 TRACE("required: 0x%lx/%ld\n", needed, needed);
4076 if(needed > cbBuf) {
4077 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4078 return FALSE;
4080 if(pcbNeeded == NULL) {
4081 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
4082 SetLastError(RPC_X_NULL_REF_POINTER);
4083 return FALSE;
4085 if(pDriverDirectory == NULL) {
4086 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
4087 SetLastError(ERROR_INVALID_USER_BUFFER);
4088 return FALSE;
4091 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
4092 /* add the Subdirectories */
4093 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
4094 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
4095 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
4096 return TRUE;
4100 /*****************************************************************************
4101 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4103 * Return the PATH for the Printer-Drivers (ANSI)
4105 * See GetPrinterDriverDirectoryW.
4107 * NOTES
4108 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4111 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4112 DWORD Level, LPBYTE pDriverDirectory,
4113 DWORD cbBuf, LPDWORD pcbNeeded)
4115 UNICODE_STRING nameW, environmentW;
4116 BOOL ret;
4117 DWORD pcbNeededW;
4118 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4119 WCHAR *driverDirectoryW = NULL;
4121 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(pName),
4122 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4124 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4126 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4127 else nameW.Buffer = NULL;
4128 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4129 else environmentW.Buffer = NULL;
4131 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4132 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4133 if (ret) {
4134 DWORD needed;
4135 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4136 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4137 if(pcbNeeded)
4138 *pcbNeeded = needed;
4139 ret = (needed <= cbBuf) ? TRUE : FALSE;
4140 } else
4141 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4143 TRACE("required: 0x%lx/%ld\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4145 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4146 RtlFreeUnicodeString(&environmentW);
4147 RtlFreeUnicodeString(&nameW);
4149 return ret;
4152 /*****************************************************************************
4153 * AddPrinterDriverA [WINSPOOL.@]
4155 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4157 DRIVER_INFO_3A di3;
4158 HKEY hkeyDrivers, hkeyName;
4159 static CHAR empty[] = "",
4160 nullnull[] = "\0";
4162 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
4164 if(level != 2 && level != 3) {
4165 SetLastError(ERROR_INVALID_LEVEL);
4166 return FALSE;
4168 if ((pName) && (pName[0])) {
4169 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
4170 SetLastError(ERROR_INVALID_PARAMETER);
4171 return FALSE;
4173 if(!pDriverInfo) {
4174 WARN("pDriverInfo == NULL\n");
4175 SetLastError(ERROR_INVALID_PARAMETER);
4176 return FALSE;
4179 if(level == 3)
4180 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
4181 else {
4182 memset(&di3, 0, sizeof(di3));
4183 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
4186 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
4187 !di3.pDataFile) {
4188 SetLastError(ERROR_INVALID_PARAMETER);
4189 return FALSE;
4192 if(!di3.pDefaultDataType) di3.pDefaultDataType = empty;
4193 if(!di3.pDependentFiles) di3.pDependentFiles = nullnull;
4194 if(!di3.pHelpFile) di3.pHelpFile = empty;
4195 if(!di3.pMonitorName) di3.pMonitorName = empty;
4197 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
4199 if(!hkeyDrivers) {
4200 ERR("Can't create Drivers key\n");
4201 return FALSE;
4204 if(level == 2) { /* apparently can't overwrite with level2 */
4205 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
4206 RegCloseKey(hkeyName);
4207 RegCloseKey(hkeyDrivers);
4208 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
4209 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
4210 return FALSE;
4213 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
4214 RegCloseKey(hkeyDrivers);
4215 ERR("Can't create Name key\n");
4216 return FALSE;
4218 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
4220 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, 0);
4221 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, 0);
4222 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
4223 sizeof(DWORD));
4224 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, 0);
4225 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
4226 (LPBYTE) di3.pDependentFiles, 0);
4227 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, 0);
4228 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, 0);
4229 RegCloseKey(hkeyName);
4230 RegCloseKey(hkeyDrivers);
4232 return TRUE;
4235 /*****************************************************************************
4236 * AddPrinterDriverW [WINSPOOL.@]
4238 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
4239 LPBYTE pDriverInfo)
4241 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
4242 level,pDriverInfo);
4243 return FALSE;
4246 /*****************************************************************************
4247 * AddPrintProcessorA [WINSPOOL.@]
4249 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4250 LPSTR pPrintProcessorName)
4252 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4253 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4254 return FALSE;
4257 /*****************************************************************************
4258 * AddPrintProcessorW [WINSPOOL.@]
4260 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4261 LPWSTR pPrintProcessorName)
4263 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4264 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4265 return FALSE;
4268 /*****************************************************************************
4269 * AddPrintProvidorA [WINSPOOL.@]
4271 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4273 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4274 return FALSE;
4277 /*****************************************************************************
4278 * AddPrintProvidorW [WINSPOOL.@]
4280 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4282 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4283 return FALSE;
4286 /*****************************************************************************
4287 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4289 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4290 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4292 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4293 pDevModeOutput, pDevModeInput);
4294 return 0;
4297 /*****************************************************************************
4298 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4300 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4301 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4303 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4304 pDevModeOutput, pDevModeInput);
4305 return 0;
4308 /*****************************************************************************
4309 * PrinterProperties [WINSPOOL.@]
4311 * Displays a dialog to set the properties of the printer.
4313 * RETURNS
4314 * nonzero on success or zero on failure
4316 * BUGS
4317 * implemented as stub only
4319 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4320 HANDLE hPrinter /* [in] handle to printer object */
4322 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4323 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4324 return FALSE;
4327 /*****************************************************************************
4328 * EnumJobsA [WINSPOOL.@]
4331 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4332 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4333 LPDWORD pcReturned)
4335 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
4336 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4338 if(pcbNeeded) *pcbNeeded = 0;
4339 if(pcReturned) *pcReturned = 0;
4340 return FALSE;
4344 /*****************************************************************************
4345 * EnumJobsW [WINSPOOL.@]
4348 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4349 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4350 LPDWORD pcReturned)
4352 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
4353 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4355 if(pcbNeeded) *pcbNeeded = 0;
4356 if(pcReturned) *pcReturned = 0;
4357 return FALSE;
4360 /*****************************************************************************
4361 * WINSPOOL_EnumPrinterDrivers [internal]
4363 * Delivers information about all printer drivers installed on the
4364 * localhost or a given server
4366 * RETURNS
4367 * nonzero on success or zero on failure. If the buffer for the returned
4368 * information is too small the function will return an error
4370 * BUGS
4371 * - only implemented for localhost, foreign hosts will return an error
4373 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
4374 DWORD Level, LPBYTE pDriverInfo,
4375 DWORD cbBuf, LPDWORD pcbNeeded,
4376 LPDWORD pcReturned, BOOL unicode)
4378 { HKEY hkeyDrivers;
4379 DWORD i, needed, number = 0, size = 0;
4380 WCHAR DriverNameW[255];
4381 PBYTE ptr;
4383 TRACE("%s,%s,%ld,%p,%ld,%d\n",
4384 debugstr_w(pName), debugstr_w(pEnvironment),
4385 Level, pDriverInfo, cbBuf, unicode);
4387 /* check for local drivers */
4388 if((pName) && (pName[0])) {
4389 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4390 SetLastError(ERROR_ACCESS_DENIED);
4391 return FALSE;
4394 /* check input parameter */
4395 if((Level < 1) || (Level > 3)) {
4396 ERR("unsupported level %ld\n", Level);
4397 SetLastError(ERROR_INVALID_LEVEL);
4398 return FALSE;
4401 /* initialize return values */
4402 if(pDriverInfo)
4403 memset( pDriverInfo, 0, cbBuf);
4404 *pcbNeeded = 0;
4405 *pcReturned = 0;
4407 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
4408 if(!hkeyDrivers) {
4409 ERR("Can't open Drivers key\n");
4410 return FALSE;
4413 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
4414 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4415 RegCloseKey(hkeyDrivers);
4416 ERR("Can't query Drivers key\n");
4417 return FALSE;
4419 TRACE("Found %ld Drivers\n", number);
4421 /* get size of single struct
4422 * unicode and ascii structure have the same size
4424 switch (Level) {
4425 case 1:
4426 size = sizeof(DRIVER_INFO_1A);
4427 break;
4428 case 2:
4429 size = sizeof(DRIVER_INFO_2A);
4430 break;
4431 case 3:
4432 size = sizeof(DRIVER_INFO_3A);
4433 break;
4436 /* calculate required buffer size */
4437 *pcbNeeded = size * number;
4439 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
4440 i < number;
4441 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
4442 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
4443 != ERROR_SUCCESS) {
4444 ERR("Can't enum key number %ld\n", i);
4445 RegCloseKey(hkeyDrivers);
4446 return FALSE;
4448 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4449 pEnvironment, Level, ptr,
4450 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
4451 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4452 &needed, unicode)) {
4453 RegCloseKey(hkeyDrivers);
4454 return FALSE;
4456 (*pcbNeeded) += needed;
4459 RegCloseKey(hkeyDrivers);
4461 if(cbBuf < *pcbNeeded){
4462 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4463 return FALSE;
4466 *pcReturned = number;
4467 return TRUE;
4470 /*****************************************************************************
4471 * EnumPrinterDriversW [WINSPOOL.@]
4473 * see function EnumPrinterDrivers for RETURNS, BUGS
4475 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4476 LPBYTE pDriverInfo, DWORD cbBuf,
4477 LPDWORD pcbNeeded, LPDWORD pcReturned)
4479 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4480 cbBuf, pcbNeeded, pcReturned, TRUE);
4483 /*****************************************************************************
4484 * EnumPrinterDriversA [WINSPOOL.@]
4486 * see function EnumPrinterDrivers for RETURNS, BUGS
4488 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4489 LPBYTE pDriverInfo, DWORD cbBuf,
4490 LPDWORD pcbNeeded, LPDWORD pcReturned)
4491 { BOOL ret;
4492 UNICODE_STRING pNameW, pEnvironmentW;
4493 PWSTR pwstrNameW, pwstrEnvironmentW;
4495 pwstrNameW = asciitounicode(&pNameW, pName);
4496 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4498 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
4499 Level, pDriverInfo, cbBuf, pcbNeeded,
4500 pcReturned, FALSE);
4501 RtlFreeUnicodeString(&pNameW);
4502 RtlFreeUnicodeString(&pEnvironmentW);
4504 return ret;
4507 static CHAR PortMonitor[] = "Wine Port Monitor";
4508 static CHAR PortDescription[] = "Wine Port";
4510 static BOOL WINSPOOL_ComPortExists( LPCSTR name )
4512 HANDLE handle;
4514 handle = CreateFileA( name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
4515 NULL, OPEN_EXISTING, 0, NULL );
4516 if (handle == INVALID_HANDLE_VALUE)
4517 return FALSE;
4518 TRACE("Checking %s exists\n", name );
4519 CloseHandle( handle );
4520 return TRUE;
4523 static DWORD WINSPOOL_CountSerialPorts(void)
4525 CHAR name[6];
4526 DWORD n = 0, i;
4528 for (i=0; i<4; i++)
4530 strcpy( name, "COMx:" );
4531 name[3] = '1' + i;
4532 if (WINSPOOL_ComPortExists( name ))
4533 n++;
4536 return n;
4539 /******************************************************************************
4540 * EnumPortsA (WINSPOOL.@)
4542 * See EnumPortsW.
4544 * BUGS
4545 * ANSI-Version did not call the UNICODE-Version
4548 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4549 LPDWORD bufneeded,LPDWORD bufreturned)
4551 CHAR portname[10];
4552 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
4553 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
4554 HKEY hkey_printer;
4555 BOOL retval = TRUE;
4557 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
4558 debugstr_a(name),level,buffer,bufsize,bufneeded,bufreturned);
4560 switch( level )
4562 case 1:
4563 info_size = sizeof (PORT_INFO_1A);
4564 break;
4565 case 2:
4566 info_size = sizeof (PORT_INFO_2A);
4567 break;
4568 default:
4569 SetLastError(ERROR_INVALID_LEVEL);
4570 return FALSE;
4573 /* see how many exist */
4575 hkey_printer = 0;
4576 serial_count = WINSPOOL_CountSerialPorts();
4577 printer_count = 0;
4579 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
4580 if ( r == ERROR_SUCCESS )
4582 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
4583 &printer_count, NULL, NULL, NULL, NULL);
4585 count = serial_count + printer_count;
4587 /* then fill in the structure info structure once
4588 we know the offset to the first string */
4590 memset( buffer, 0, bufsize );
4591 n = 0;
4592 ofs = info_size*count;
4593 for ( i=0; i<count; i++)
4595 DWORD vallen = sizeof(portname) - 1;
4597 /* get the serial port values, then the printer values */
4598 if ( i < serial_count )
4600 strcpy( portname, "COMx:" );
4601 portname[3] = '1' + i;
4602 if (!WINSPOOL_ComPortExists( portname ))
4603 continue;
4605 TRACE("Found %s\n", portname );
4606 vallen = strlen( portname );
4608 else
4610 r = RegEnumValueA( hkey_printer, i-serial_count,
4611 portname, &vallen, NULL, NULL, NULL, 0 );
4612 if ( r )
4613 continue;
4616 /* add a colon if necessary, and make it upper case */
4617 CharUpperBuffA(portname,vallen);
4618 if (strcasecmp(portname,"nul")!=0)
4619 if (vallen && (portname[vallen-1] != ':') )
4620 lstrcatA(portname,":");
4622 /* add the port info structure if we can fit it */
4623 if ( info_size*(n+1) < bufsize )
4625 if ( level == 1)
4627 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
4628 info->pName = (LPSTR) &buffer[ofs];
4630 else if ( level == 2)
4632 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
4633 info->pPortName = (LPSTR) &buffer[ofs];
4634 /* FIXME: fill in more stuff here */
4635 info->pMonitorName = PortMonitor;
4636 info->pDescription = PortDescription;
4637 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
4640 /* add the name of the port if we can fit it */
4641 if ( ofs < bufsize )
4642 lstrcpynA((LPSTR)&buffer[ofs],portname,bufsize - ofs);
4644 n++;
4646 else
4647 retval = FALSE;
4648 ofs += lstrlenA(portname)+1;
4651 RegCloseKey(hkey_printer);
4653 if(bufneeded)
4654 *bufneeded = ofs;
4656 if(bufreturned)
4657 *bufreturned = n;
4659 return retval;
4662 /******************************************************************************
4663 * EnumPortsW (WINSPOOL.@)
4665 * Enumerate available Ports
4667 * PARAMS
4668 * name [I] Servername or NULL (local Computer)
4669 * level [I] Structure-Level (1 or 2)
4670 * buffer [O] PTR to Buffer that receives the Result
4671 * bufsize [I] Size of Buffer at buffer
4672 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
4673 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
4675 * RETURNS
4676 * Success: TRUE
4677 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
4679 * BUGS
4680 * UNICODE-Version is a stub
4683 BOOL WINAPI EnumPortsW(LPWSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4684 LPDWORD bufneeded,LPDWORD bufreturned)
4686 FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
4687 debugstr_w(name),level,buffer,bufsize,bufneeded,bufreturned);
4688 return FALSE;
4691 /******************************************************************************
4692 * GetDefaultPrinterW (WINSPOOL.@)
4694 * FIXME
4695 * This function must read the value from data 'device' of key
4696 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
4698 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
4700 BOOL retval = TRUE;
4701 DWORD insize, len;
4702 WCHAR *buffer, *ptr;
4704 if (!namesize)
4706 SetLastError(ERROR_INVALID_PARAMETER);
4707 return FALSE;
4710 /* make the buffer big enough for the stuff from the profile/registry,
4711 * the content must fit into the local buffer to compute the correct
4712 * size even if the extern buffer is too small or not given.
4713 * (20 for ,driver,port) */
4714 insize = *namesize;
4715 len = max(100, (insize + 20));
4716 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
4718 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
4720 SetLastError (ERROR_FILE_NOT_FOUND);
4721 retval = FALSE;
4722 goto end;
4724 TRACE("%s\n", debugstr_w(buffer));
4726 if ((ptr = strchrW(buffer, ',')) == NULL)
4728 SetLastError(ERROR_INVALID_NAME);
4729 retval = FALSE;
4730 goto end;
4733 *ptr = 0;
4734 *namesize = strlenW(buffer) + 1;
4735 if(!name || (*namesize > insize))
4737 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4738 retval = FALSE;
4739 goto end;
4741 strcpyW(name, buffer);
4743 end:
4744 HeapFree( GetProcessHeap(), 0, buffer);
4745 return retval;
4749 /******************************************************************************
4750 * GetDefaultPrinterA (WINSPOOL.@)
4752 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
4754 BOOL retval = TRUE;
4755 DWORD insize = 0;
4756 WCHAR *bufferW = NULL;
4758 if (!namesize)
4760 SetLastError(ERROR_INVALID_PARAMETER);
4761 return FALSE;
4764 if(name && *namesize) {
4765 insize = *namesize;
4766 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
4769 if(!GetDefaultPrinterW( bufferW, namesize)) {
4770 retval = FALSE;
4771 goto end;
4774 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
4775 NULL, NULL);
4776 if (!*namesize)
4778 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
4779 retval = FALSE;
4781 TRACE("0x%08lx/0x%08lx:%s\n", *namesize, insize, debugstr_w(bufferW));
4783 end:
4784 HeapFree( GetProcessHeap(), 0, bufferW);
4785 return retval;
4789 /******************************************************************************
4790 * SetDefaultPrinterW (WINSPOOL.204)
4792 * Set the Name of the Default Printer
4794 * PARAMS
4795 * pszPrinter [I] Name of the Printer or NULL
4797 * RETURNS
4798 * Success: True
4799 * Failure: FALSE
4801 * NOTES
4802 * When the Parameter is NULL or points to an Empty String and
4803 * a Default Printer was already present, then this Function changes nothing.
4804 * Without a Default Printer and NULL (or an Empty String) as Parameter,
4805 * the First enumerated local Printer is used.
4808 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
4811 TRACE("(%s)\n", debugstr_w(pszPrinter));
4813 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4814 return FALSE;
4817 /******************************************************************************
4818 * SetDefaultPrinterA (WINSPOOL.202)
4820 * See SetDefaultPrinterW.
4823 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
4826 TRACE("(%s)\n", debugstr_a(pszPrinter));
4828 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4829 return FALSE;
4833 /******************************************************************************
4834 * SetPrinterDataExA (WINSPOOL.@)
4836 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4837 LPCSTR pValueName, DWORD Type,
4838 LPBYTE pData, DWORD cbData)
4840 HKEY hkeyPrinter, hkeySubkey;
4841 DWORD ret;
4843 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
4844 debugstr_a(pValueName), Type, pData, cbData);
4846 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4847 != ERROR_SUCCESS)
4848 return ret;
4850 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4851 != ERROR_SUCCESS) {
4852 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
4853 RegCloseKey(hkeyPrinter);
4854 return ret;
4856 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
4857 RegCloseKey(hkeySubkey);
4858 RegCloseKey(hkeyPrinter);
4859 return ret;
4862 /******************************************************************************
4863 * SetPrinterDataExW (WINSPOOL.@)
4865 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4866 LPCWSTR pValueName, DWORD Type,
4867 LPBYTE pData, DWORD cbData)
4869 HKEY hkeyPrinter, hkeySubkey;
4870 DWORD ret;
4872 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
4873 debugstr_w(pValueName), Type, pData, cbData);
4875 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4876 != ERROR_SUCCESS)
4877 return ret;
4879 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4880 != ERROR_SUCCESS) {
4881 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
4882 RegCloseKey(hkeyPrinter);
4883 return ret;
4885 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
4886 RegCloseKey(hkeySubkey);
4887 RegCloseKey(hkeyPrinter);
4888 return ret;
4891 /******************************************************************************
4892 * SetPrinterDataA (WINSPOOL.@)
4894 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
4895 LPBYTE pData, DWORD cbData)
4897 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
4898 pData, cbData);
4901 /******************************************************************************
4902 * SetPrinterDataW (WINSPOOL.@)
4904 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
4905 LPBYTE pData, DWORD cbData)
4907 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
4908 pData, cbData);
4911 /******************************************************************************
4912 * GetPrinterDataExA (WINSPOOL.@)
4914 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4915 LPCSTR pValueName, LPDWORD pType,
4916 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4918 HKEY hkeyPrinter, hkeySubkey;
4919 DWORD ret;
4921 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4922 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
4923 pcbNeeded);
4925 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4926 != ERROR_SUCCESS)
4927 return ret;
4929 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4930 != ERROR_SUCCESS) {
4931 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
4932 RegCloseKey(hkeyPrinter);
4933 return ret;
4935 *pcbNeeded = nSize;
4936 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4937 RegCloseKey(hkeySubkey);
4938 RegCloseKey(hkeyPrinter);
4939 return ret;
4942 /******************************************************************************
4943 * GetPrinterDataExW (WINSPOOL.@)
4945 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4946 LPCWSTR pValueName, LPDWORD pType,
4947 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4949 HKEY hkeyPrinter, hkeySubkey;
4950 DWORD ret;
4952 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4953 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
4954 pcbNeeded);
4956 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4957 != ERROR_SUCCESS)
4958 return ret;
4960 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4961 != ERROR_SUCCESS) {
4962 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
4963 RegCloseKey(hkeyPrinter);
4964 return ret;
4966 *pcbNeeded = nSize;
4967 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4968 RegCloseKey(hkeySubkey);
4969 RegCloseKey(hkeyPrinter);
4970 return ret;
4973 /******************************************************************************
4974 * GetPrinterDataA (WINSPOOL.@)
4976 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
4977 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4979 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
4980 pData, nSize, pcbNeeded);
4983 /******************************************************************************
4984 * GetPrinterDataW (WINSPOOL.@)
4986 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
4987 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4989 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
4990 pData, nSize, pcbNeeded);
4993 /*******************************************************************************
4994 * EnumPrinterDataExW [WINSPOOL.@]
4996 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4997 LPBYTE pEnumValues, DWORD cbEnumValues,
4998 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5000 HKEY hkPrinter, hkSubKey;
5001 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5002 cbValueNameLen, cbMaxValueLen, cbValueLen,
5003 cbBufSize, dwType;
5004 LPWSTR lpValueName;
5005 HANDLE hHeap;
5006 PBYTE lpValue;
5007 PPRINTER_ENUM_VALUESW ppev;
5009 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5011 if (pKeyName == NULL || *pKeyName == 0)
5012 return ERROR_INVALID_PARAMETER;
5014 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5015 if (ret != ERROR_SUCCESS)
5017 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
5018 hPrinter, ret);
5019 return ret;
5022 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5023 if (ret != ERROR_SUCCESS)
5025 r = RegCloseKey (hkPrinter);
5026 if (r != ERROR_SUCCESS)
5027 WARN ("RegCloseKey returned %li\n", r);
5028 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
5029 debugstr_w (pKeyName), ret);
5030 return ret;
5033 ret = RegCloseKey (hkPrinter);
5034 if (ret != ERROR_SUCCESS)
5036 ERR ("RegCloseKey returned %li\n", ret);
5037 r = RegCloseKey (hkSubKey);
5038 if (r != ERROR_SUCCESS)
5039 WARN ("RegCloseKey returned %li\n", r);
5040 return ret;
5043 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5044 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5045 if (ret != ERROR_SUCCESS)
5047 r = RegCloseKey (hkSubKey);
5048 if (r != ERROR_SUCCESS)
5049 WARN ("RegCloseKey returned %li\n", r);
5050 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
5051 return ret;
5054 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
5055 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5057 if (cValues == 0) /* empty key */
5059 r = RegCloseKey (hkSubKey);
5060 if (r != ERROR_SUCCESS)
5061 WARN ("RegCloseKey returned %li\n", r);
5062 *pcbEnumValues = *pnEnumValues = 0;
5063 return ERROR_SUCCESS;
5066 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5068 hHeap = GetProcessHeap ();
5069 if (hHeap == NULL)
5071 ERR ("GetProcessHeap failed\n");
5072 r = RegCloseKey (hkSubKey);
5073 if (r != ERROR_SUCCESS)
5074 WARN ("RegCloseKey returned %li\n", r);
5075 return ERROR_OUTOFMEMORY;
5078 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5079 if (lpValueName == NULL)
5081 ERR ("Failed to allocate %li bytes from process heap\n",
5082 cbMaxValueNameLen * sizeof (WCHAR));
5083 r = RegCloseKey (hkSubKey);
5084 if (r != ERROR_SUCCESS)
5085 WARN ("RegCloseKey returned %li\n", r);
5086 return ERROR_OUTOFMEMORY;
5089 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5090 if (lpValue == NULL)
5092 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
5093 if (HeapFree (hHeap, 0, lpValueName) == 0)
5094 WARN ("HeapFree failed with code %li\n", GetLastError ());
5095 r = RegCloseKey (hkSubKey);
5096 if (r != ERROR_SUCCESS)
5097 WARN ("RegCloseKey returned %li\n", r);
5098 return ERROR_OUTOFMEMORY;
5101 TRACE ("pass 1: calculating buffer required for all names and values\n");
5103 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5105 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
5107 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5109 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5110 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5111 NULL, NULL, lpValue, &cbValueLen);
5112 if (ret != ERROR_SUCCESS)
5114 if (HeapFree (hHeap, 0, lpValue) == 0)
5115 WARN ("HeapFree failed with code %li\n", GetLastError ());
5116 if (HeapFree (hHeap, 0, lpValueName) == 0)
5117 WARN ("HeapFree failed with code %li\n", GetLastError ());
5118 r = RegCloseKey (hkSubKey);
5119 if (r != ERROR_SUCCESS)
5120 WARN ("RegCloseKey returned %li\n", r);
5121 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
5122 return ret;
5125 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
5126 debugstr_w (lpValueName), dwIndex,
5127 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
5129 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5130 cbBufSize += cbValueLen;
5133 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
5135 *pcbEnumValues = cbBufSize;
5136 *pnEnumValues = cValues;
5138 if (cbEnumValues < cbBufSize) /* buffer too small */
5140 if (HeapFree (hHeap, 0, lpValue) == 0)
5141 WARN ("HeapFree failed with code %li\n", GetLastError ());
5142 if (HeapFree (hHeap, 0, lpValueName) == 0)
5143 WARN ("HeapFree failed with code %li\n", GetLastError ());
5144 r = RegCloseKey (hkSubKey);
5145 if (r != ERROR_SUCCESS)
5146 WARN ("RegCloseKey returned %li\n", r);
5147 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
5148 return ERROR_MORE_DATA;
5151 TRACE ("pass 2: copying all names and values to buffer\n");
5153 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5154 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5156 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5158 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5159 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5160 NULL, &dwType, lpValue, &cbValueLen);
5161 if (ret != ERROR_SUCCESS)
5163 if (HeapFree (hHeap, 0, lpValue) == 0)
5164 WARN ("HeapFree failed with code %li\n", GetLastError ());
5165 if (HeapFree (hHeap, 0, lpValueName) == 0)
5166 WARN ("HeapFree failed with code %li\n", GetLastError ());
5167 r = RegCloseKey (hkSubKey);
5168 if (r != ERROR_SUCCESS)
5169 WARN ("RegCloseKey returned %li\n", r);
5170 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
5171 return ret;
5174 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5175 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5176 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5177 pEnumValues += cbValueNameLen;
5179 /* return # of *bytes* (including trailing \0), not # of chars */
5180 ppev[dwIndex].cbValueName = cbValueNameLen;
5182 ppev[dwIndex].dwType = dwType;
5184 memcpy (pEnumValues, lpValue, cbValueLen);
5185 ppev[dwIndex].pData = pEnumValues;
5186 pEnumValues += cbValueLen;
5188 ppev[dwIndex].cbData = cbValueLen;
5190 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
5191 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5194 if (HeapFree (hHeap, 0, lpValue) == 0)
5196 ret = GetLastError ();
5197 ERR ("HeapFree failed with code %li\n", ret);
5198 if (HeapFree (hHeap, 0, lpValueName) == 0)
5199 WARN ("HeapFree failed with code %li\n", GetLastError ());
5200 r = RegCloseKey (hkSubKey);
5201 if (r != ERROR_SUCCESS)
5202 WARN ("RegCloseKey returned %li\n", r);
5203 return ret;
5206 if (HeapFree (hHeap, 0, lpValueName) == 0)
5208 ret = GetLastError ();
5209 ERR ("HeapFree failed with code %li\n", ret);
5210 r = RegCloseKey (hkSubKey);
5211 if (r != ERROR_SUCCESS)
5212 WARN ("RegCloseKey returned %li\n", r);
5213 return ret;
5216 ret = RegCloseKey (hkSubKey);
5217 if (ret != ERROR_SUCCESS)
5219 ERR ("RegCloseKey returned %li\n", ret);
5220 return ret;
5223 return ERROR_SUCCESS;
5226 /*******************************************************************************
5227 * EnumPrinterDataExA [WINSPOOL.@]
5229 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5230 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5231 * what Windows 2000 SP1 does.
5234 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5235 LPBYTE pEnumValues, DWORD cbEnumValues,
5236 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5238 INT len;
5239 LPWSTR pKeyNameW;
5240 DWORD ret, dwIndex, dwBufSize;
5241 HANDLE hHeap;
5242 LPSTR pBuffer;
5244 TRACE ("%p %s\n", hPrinter, pKeyName);
5246 if (pKeyName == NULL || *pKeyName == 0)
5247 return ERROR_INVALID_PARAMETER;
5249 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5250 if (len == 0)
5252 ret = GetLastError ();
5253 ERR ("MultiByteToWideChar failed with code %li\n", ret);
5254 return ret;
5257 hHeap = GetProcessHeap ();
5258 if (hHeap == NULL)
5260 ERR ("GetProcessHeap failed\n");
5261 return ERROR_OUTOFMEMORY;
5264 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5265 if (pKeyNameW == NULL)
5267 ERR ("Failed to allocate %li bytes from process heap\n",
5268 (LONG) len * sizeof (WCHAR));
5269 return ERROR_OUTOFMEMORY;
5272 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5274 ret = GetLastError ();
5275 ERR ("MultiByteToWideChar failed with code %li\n", ret);
5276 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5277 WARN ("HeapFree failed with code %li\n", GetLastError ());
5278 return ret;
5281 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5282 pcbEnumValues, pnEnumValues);
5283 if (ret != ERROR_SUCCESS)
5285 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5286 WARN ("HeapFree failed with code %li\n", GetLastError ());
5287 TRACE ("EnumPrinterDataExW returned %li\n", ret);
5288 return ret;
5291 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5293 ret = GetLastError ();
5294 ERR ("HeapFree failed with code %li\n", ret);
5295 return ret;
5298 if (*pnEnumValues == 0) /* empty key */
5299 return ERROR_SUCCESS;
5301 dwBufSize = 0;
5302 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5304 PPRINTER_ENUM_VALUESW ppev =
5305 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5307 if (dwBufSize < ppev->cbValueName)
5308 dwBufSize = ppev->cbValueName;
5310 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5311 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5312 dwBufSize = ppev->cbData;
5315 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
5317 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5318 if (pBuffer == NULL)
5320 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
5321 return ERROR_OUTOFMEMORY;
5324 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5326 PPRINTER_ENUM_VALUESW ppev =
5327 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5329 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5330 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5331 NULL);
5332 if (len == 0)
5334 ret = GetLastError ();
5335 ERR ("WideCharToMultiByte failed with code %li\n", ret);
5336 if (HeapFree (hHeap, 0, pBuffer) == 0)
5337 WARN ("HeapFree failed with code %li\n", GetLastError ());
5338 return ret;
5341 memcpy (ppev->pValueName, pBuffer, len);
5343 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5345 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5346 ppev->dwType != REG_MULTI_SZ)
5347 continue;
5349 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5350 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5351 if (len == 0)
5353 ret = GetLastError ();
5354 ERR ("WideCharToMultiByte failed with code %li\n", ret);
5355 if (HeapFree (hHeap, 0, pBuffer) == 0)
5356 WARN ("HeapFree failed with code %li\n", GetLastError ());
5357 return ret;
5360 memcpy (ppev->pData, pBuffer, len);
5362 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5363 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5366 if (HeapFree (hHeap, 0, pBuffer) == 0)
5368 ret = GetLastError ();
5369 ERR ("HeapFree failed with code %li\n", ret);
5370 return ret;
5373 return ERROR_SUCCESS;
5376 /******************************************************************************
5377 * AbortPrinter (WINSPOOL.@)
5379 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5381 FIXME("(%p), stub!\n", hPrinter);
5382 return TRUE;
5385 /******************************************************************************
5386 * AddPortA (WINSPOOL.@)
5388 * See AddPortW.
5391 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5393 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName),hWnd,debugstr_a(pMonitorName));
5394 return FALSE;
5397 /******************************************************************************
5398 * AddPortW (WINSPOOL.@)
5400 * Add a Port for a specific Monitor
5402 * PARAMS
5403 * pName [I] Servername or NULL (local Computer)
5404 * hWnd [I] Handle to parent Window for the Dialog-Box
5405 * pMonitorName [I] Name of the Monitor that manage the Port
5407 * RETURNS
5408 * Success: TRUE
5409 * Failure: FALSE
5411 * BUGS
5412 * only a Stub
5415 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5417 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName),hWnd,debugstr_w(pMonitorName));
5418 return FALSE;
5421 /******************************************************************************
5422 * AddPortExA (WINSPOOL.@)
5424 * See AddPortExW.
5427 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
5429 FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
5430 lpBuffer, debugstr_a(lpMonitorName));
5431 return FALSE;
5434 /******************************************************************************
5435 * AddPortExW (WINSPOOL.@)
5437 * Add a Port for a specific Monitor, without presenting a user interface
5439 * PARAMS
5440 * hMonitor [I] Handle from InitializePrintMonitor2()
5441 * pName [I] Servername or NULL (local Computer)
5442 * Level [I] Structure-Level (1 or 2) for lpBuffer
5443 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
5444 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
5446 * RETURNS
5447 * Success: TRUE
5448 * Failure: FALSE
5450 * BUGS
5451 * only a Stub
5454 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
5456 FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
5457 lpBuffer, debugstr_w(lpMonitorName));
5458 return FALSE;
5461 /******************************************************************************
5462 * AddPrinterConnectionA (WINSPOOL.@)
5464 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
5466 FIXME("%s\n", debugstr_a(pName));
5467 return FALSE;
5470 /******************************************************************************
5471 * AddPrinterConnectionW (WINSPOOL.@)
5473 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
5475 FIXME("%s\n", debugstr_w(pName));
5476 return FALSE;
5479 /******************************************************************************
5480 * AddPrinterDriverExW (WINSPOOL.@)
5482 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
5483 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5485 FIXME("%s %ld %p %ld\n", debugstr_w(pName),
5486 Level, pDriverInfo, dwFileCopyFlags);
5487 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5488 return FALSE;
5491 /******************************************************************************
5492 * AddPrinterDriverExA (WINSPOOL.@)
5494 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
5495 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5497 FIXME("%s %ld %p %ld\n", debugstr_a(pName),
5498 Level, pDriverInfo, dwFileCopyFlags);
5499 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5500 return FALSE;
5503 /******************************************************************************
5504 * ConfigurePortA (WINSPOOL.@)
5506 * See ConfigurePortW.
5509 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
5511 FIXME("%s %p %s\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
5512 return FALSE;
5515 /******************************************************************************
5516 * ConfigurePortW (WINSPOOL.@)
5518 * Display the Configuration-Dialog for a specific Port
5520 * PARAMS
5521 * pName [I] Servername or NULL (local Computer)
5522 * hWnd [I] Handle to parent Window for the Dialog-Box
5523 * pPortName [I] Name of the Port, that should be configured
5525 * RETURNS
5526 * Success: TRUE
5527 * Failure: FALSE
5529 * BUGS
5530 * only a Stub
5533 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
5535 FIXME("%s %p %s\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
5536 return FALSE;
5539 /******************************************************************************
5540 * ConnectToPrinterDlg (WINSPOOL.@)
5542 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
5544 FIXME("%p %lx\n", hWnd, Flags);
5545 return NULL;
5548 /******************************************************************************
5549 * DeletePrinterConnectionA (WINSPOOL.@)
5551 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
5553 FIXME("%s\n", debugstr_a(pName));
5554 return TRUE;
5557 /******************************************************************************
5558 * DeletePrinterConnectionW (WINSPOOL.@)
5560 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
5562 FIXME("%s\n", debugstr_w(pName));
5563 return TRUE;
5566 /******************************************************************************
5567 * DeletePrinterDriverExW (WINSPOOL.@)
5569 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
5570 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5572 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
5573 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
5574 return TRUE;
5577 /******************************************************************************
5578 * DeletePrinterDriverExA (WINSPOOL.@)
5580 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
5581 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5583 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName), debugstr_a(pEnvironment),
5584 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
5585 return TRUE;
5588 /******************************************************************************
5589 * DeletePrinterDataExW (WINSPOOL.@)
5591 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
5592 LPCWSTR pValueName)
5594 FIXME("%p %s %s\n", hPrinter,
5595 debugstr_w(pKeyName), debugstr_w(pValueName));
5596 return ERROR_INVALID_PARAMETER;
5599 /******************************************************************************
5600 * DeletePrinterDataExA (WINSPOOL.@)
5602 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
5603 LPCSTR pValueName)
5605 FIXME("%p %s %s\n", hPrinter,
5606 debugstr_a(pKeyName), debugstr_a(pValueName));
5607 return ERROR_INVALID_PARAMETER;
5610 /******************************************************************************
5611 * DeletePrintProcessorA (WINSPOOL.@)
5613 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
5615 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5616 debugstr_a(pPrintProcessorName));
5617 return TRUE;
5620 /******************************************************************************
5621 * DeletePrintProcessorW (WINSPOOL.@)
5623 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
5625 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5626 debugstr_w(pPrintProcessorName));
5627 return TRUE;
5630 /******************************************************************************
5631 * DeletePrintProvidorA (WINSPOOL.@)
5633 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
5635 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5636 debugstr_a(pPrintProviderName));
5637 return TRUE;
5640 /******************************************************************************
5641 * DeletePrintProvidorW (WINSPOOL.@)
5643 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
5645 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5646 debugstr_w(pPrintProviderName));
5647 return TRUE;
5650 /******************************************************************************
5651 * EnumFormsA (WINSPOOL.@)
5653 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5654 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5656 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5657 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5658 return FALSE;
5661 /******************************************************************************
5662 * EnumFormsW (WINSPOOL.@)
5664 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5665 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5667 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5668 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5669 return FALSE;
5672 /*****************************************************************************
5673 * EnumMonitorsA [WINSPOOL.@]
5675 * See EnumMonitorsW.
5678 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
5679 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5681 BOOL res;
5682 LPBYTE bufferW = NULL;
5683 LPWSTR nameW = NULL;
5684 DWORD needed = 0;
5685 DWORD numentries = 0;
5686 INT len;
5688 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
5689 cbBuf, pcbNeeded, pcReturned);
5691 /* convert servername to unicode */
5692 if (pName) {
5693 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5694 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5695 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5697 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
5698 needed = cbBuf * sizeof(WCHAR);
5699 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5700 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5702 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5703 if (pcbNeeded) needed = *pcbNeeded;
5704 /* HeapReAlloc return NULL, when bufferW was NULL */
5705 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5706 HeapAlloc(GetProcessHeap(), 0, needed);
5708 /* Try again with the large Buffer */
5709 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5711 numentries = pcReturned ? *pcReturned : 0;
5712 needed = 0;
5714 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
5715 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5717 if (res) {
5718 /* EnumMonitorsW collected all Data. Parse them to caclulate ANSI-Size */
5719 DWORD entrysize = 0;
5720 DWORD index;
5721 LPSTR ptr;
5722 LPMONITOR_INFO_2W mi2w;
5723 LPMONITOR_INFO_2A mi2a;
5725 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
5726 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
5728 /* First pass: calculate the size for all Entries */
5729 mi2w = (LPMONITOR_INFO_2W) bufferW;
5730 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5731 index = 0;
5732 while (index < numentries) {
5733 index++;
5734 needed += entrysize; /* MONITOR_INFO_?A */
5735 TRACE("%p: parsing #%ld (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
5737 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5738 NULL, 0, NULL, NULL);
5739 if (Level > 1) {
5740 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5741 NULL, 0, NULL, NULL);
5742 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5743 NULL, 0, NULL, NULL);
5745 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5746 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5747 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
5750 /* check for errors and quit on failure */
5751 if (cbBuf < needed) {
5752 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5753 res = FALSE;
5754 goto emA_cleanup;
5756 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
5757 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
5758 cbBuf -= len ; /* free Bytes in the user-Buffer */
5759 mi2w = (LPMONITOR_INFO_2W) bufferW;
5760 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5761 index = 0;
5762 /* Second Pass: Fill the User Buffer (if we have one) */
5763 while ((index < numentries) && pMonitors) {
5764 index++;
5765 TRACE("%p: writing MONITOR_INFO_%ldA #%ld\n", mi2a, Level, index);
5766 mi2a->pName = ptr;
5767 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5768 ptr, cbBuf , NULL, NULL);
5769 ptr += len;
5770 cbBuf -= len;
5771 if (Level > 1) {
5772 mi2a->pEnvironment = ptr;
5773 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5774 ptr, cbBuf, NULL, NULL);
5775 ptr += len;
5776 cbBuf -= len;
5778 mi2a->pDLLName = ptr;
5779 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5780 ptr, cbBuf, NULL, NULL);
5781 ptr += len;
5782 cbBuf -= len;
5784 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5785 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5786 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
5789 emA_cleanup:
5790 if (pcbNeeded) *pcbNeeded = needed;
5791 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5793 HeapFree(GetProcessHeap(), 0, nameW);
5794 HeapFree(GetProcessHeap(), 0, bufferW);
5796 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
5797 (res), GetLastError(), needed, numentries);
5799 return (res);
5803 /*****************************************************************************
5804 * EnumMonitorsW [WINSPOOL.@]
5806 * Enumerate available Port-Monitors
5808 * PARAMS
5809 * pName [I] Servername or NULL (local Computer)
5810 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
5811 * pMonitors [O] PTR to Buffer that receives the Result
5812 * cbBuf [I] Size of Buffer at pMonitors
5813 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
5814 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
5816 * RETURNS
5817 * Success: TRUE
5818 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
5820 * NOTES
5821 * Windows reads the Registry once and cache the Results.
5823 *| Language-Monitors are also installed in the same Registry-Location but
5824 *| they are filtered in Windows (not returned by EnumMonitors).
5825 *| We do no filtering to simplify our Code.
5828 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
5829 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5831 DWORD needed = 0;
5832 DWORD numentries = 0;
5833 BOOL res = FALSE;
5835 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
5836 cbBuf, pcbNeeded, pcReturned);
5838 if (pName && (lstrlenW(pName))) {
5839 FIXME("for Server %s not implemented\n", debugstr_w(pName));
5840 SetLastError(ERROR_ACCESS_DENIED);
5841 goto emW_cleanup;
5844 /* Level is not checked in win9x */
5845 if (!Level || (Level > 2)) {
5846 WARN("level (%ld) is ignored in win9x\n", Level);
5847 SetLastError(ERROR_INVALID_LEVEL);
5848 goto emW_cleanup;
5850 if (!pcbNeeded) {
5851 SetLastError(RPC_X_NULL_REF_POINTER);
5852 goto emW_cleanup;
5855 /* Scan all Monitor-Keys */
5856 numentries = 0;
5857 needed = get_local_monitors(Level, NULL, 0, &numentries);
5859 /* we calculated the needed buffersize. now do the error-checks */
5860 if (cbBuf < needed) {
5861 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5862 goto emW_cleanup;
5864 else if (!pMonitors || !pcReturned) {
5865 SetLastError(RPC_X_NULL_REF_POINTER);
5866 goto emW_cleanup;
5869 /* fill the Buffer with the Monitor-Keys */
5870 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
5871 res = TRUE;
5873 emW_cleanup:
5874 if (pcbNeeded) *pcbNeeded = needed;
5875 if (pcReturned) *pcReturned = numentries;
5877 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
5878 res, GetLastError(), needed, numentries);
5880 return (res);
5883 /******************************************************************************
5884 * XcvDataW (WINSPOOL.@)
5886 * Notes:
5887 * There doesn't seem to be an A version...
5889 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
5890 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
5891 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
5893 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv, debugstr_w(pszDataName),
5894 pInputData, cbInputData, pOutputData,
5895 cbOutputData, pcbOutputNeeded, pdwStatus);
5896 return FALSE;
5899 /*****************************************************************************
5900 * EnumPrinterDataA [WINSPOOL.@]
5903 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
5904 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5905 DWORD cbData, LPDWORD pcbData )
5907 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5908 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5909 return ERROR_NO_MORE_ITEMS;
5912 /*****************************************************************************
5913 * EnumPrinterDataW [WINSPOOL.@]
5916 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
5917 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5918 DWORD cbData, LPDWORD pcbData )
5920 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5921 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5922 return ERROR_NO_MORE_ITEMS;
5925 /*****************************************************************************
5926 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
5929 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
5930 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5931 LPDWORD pcbNeeded, LPDWORD pcReturned)
5933 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName),
5934 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
5935 pcbNeeded, pcReturned);
5936 return FALSE;
5939 /*****************************************************************************
5940 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
5943 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
5944 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5945 LPDWORD pcbNeeded, LPDWORD pcReturned)
5947 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5948 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
5949 pcbNeeded, pcReturned);
5950 return FALSE;
5953 /*****************************************************************************
5954 * EnumPrintProcessorsA [WINSPOOL.@]
5957 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5958 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5960 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName, pEnvironment, Level,
5961 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
5962 return FALSE;
5965 /*****************************************************************************
5966 * EnumPrintProcessorsW [WINSPOOL.@]
5969 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5970 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5972 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5973 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
5974 cbBuf, pcbNeeded, pcbReturned);
5975 return FALSE;
5978 /*****************************************************************************
5979 * ExtDeviceMode [WINSPOOL.@]
5982 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
5983 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
5984 DWORD fMode)
5986 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd, hInst, pDevModeOutput,
5987 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
5988 debugstr_a(pProfile), fMode);
5989 return -1;
5992 /*****************************************************************************
5993 * FindClosePrinterChangeNotification [WINSPOOL.@]
5996 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
5998 FIXME("Stub: %p\n", hChange);
5999 return TRUE;
6002 /*****************************************************************************
6003 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6006 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
6007 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
6009 FIXME("Stub: %p %lx %lx %p\n",
6010 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
6011 return INVALID_HANDLE_VALUE;
6014 /*****************************************************************************
6015 * FindNextPrinterChangeNotification [WINSPOOL.@]
6018 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
6019 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
6021 FIXME("Stub: %p %p %p %p\n",
6022 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
6023 return FALSE;
6026 /*****************************************************************************
6027 * FreePrinterNotifyInfo [WINSPOOL.@]
6030 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
6032 FIXME("Stub: %p\n", pPrinterNotifyInfo);
6033 return TRUE;
6036 /*****************************************************************************
6037 * string_to_buf
6039 * Copies a unicode string into a buffer. The buffer will either contain unicode or
6040 * ansi depending on the unicode parameter.
6042 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
6044 if(!str)
6046 *size = 0;
6047 return TRUE;
6050 if(unicode)
6052 *size = (strlenW(str) + 1) * sizeof(WCHAR);
6053 if(*size <= cb)
6055 memcpy(ptr, str, *size);
6056 return TRUE;
6058 return FALSE;
6060 else
6062 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
6063 if(*size <= cb)
6065 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
6066 return TRUE;
6068 return FALSE;
6072 /*****************************************************************************
6073 * get_job_info_1
6075 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
6076 LPDWORD pcbNeeded, BOOL unicode)
6078 DWORD size, left = cbBuf;
6079 BOOL space = (cbBuf > 0);
6080 LPBYTE ptr = buf;
6082 *pcbNeeded = 0;
6084 if(space)
6086 ji1->JobId = job->job_id;
6089 string_to_buf(job->document_title, ptr, left, &size, unicode);
6090 if(space && size <= left)
6092 ji1->pDocument = (LPWSTR)ptr;
6093 ptr += size;
6094 left -= size;
6096 else
6097 space = FALSE;
6098 *pcbNeeded += size;
6100 return space;
6103 /*****************************************************************************
6104 * get_job_info_2
6106 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
6107 LPDWORD pcbNeeded, BOOL unicode)
6109 DWORD size, left = cbBuf;
6110 BOOL space = (cbBuf > 0);
6111 LPBYTE ptr = buf;
6113 *pcbNeeded = 0;
6115 if(space)
6117 ji2->JobId = job->job_id;
6120 string_to_buf(job->document_title, ptr, left, &size, unicode);
6121 if(space && size <= left)
6123 ji2->pDocument = (LPWSTR)ptr;
6124 ptr += size;
6125 left -= size;
6127 else
6128 space = FALSE;
6129 *pcbNeeded += size;
6131 return space;
6134 /*****************************************************************************
6135 * get_job_info
6137 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6138 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
6140 BOOL ret = FALSE;
6141 DWORD needed = 0, size;
6142 job_t *job;
6143 LPBYTE ptr = pJob;
6145 TRACE("%p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
6147 EnterCriticalSection(&printer_handles_cs);
6148 job = get_job(hPrinter, JobId);
6149 if(!job)
6150 goto end;
6152 switch(Level)
6154 case 1:
6155 size = sizeof(JOB_INFO_1W);
6156 if(cbBuf >= size)
6158 cbBuf -= size;
6159 ptr += size;
6160 memset(pJob, 0, size);
6162 else
6163 cbBuf = 0;
6164 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
6165 needed += size;
6166 break;
6168 case 2:
6169 size = sizeof(JOB_INFO_2W);
6170 if(cbBuf >= size)
6172 cbBuf -= size;
6173 ptr += size;
6174 memset(pJob, 0, size);
6176 else
6177 cbBuf = 0;
6178 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
6179 needed += size;
6180 break;
6182 case 3:
6183 size = sizeof(JOB_INFO_3);
6184 if(cbBuf >= size)
6186 cbBuf -= size;
6187 memset(pJob, 0, size);
6188 ret = TRUE;
6190 else
6191 cbBuf = 0;
6192 needed = size;
6193 break;
6195 default:
6196 SetLastError(ERROR_INVALID_LEVEL);
6197 goto end;
6199 if(pcbNeeded)
6200 *pcbNeeded = needed;
6201 end:
6202 LeaveCriticalSection(&printer_handles_cs);
6203 return ret;
6206 /*****************************************************************************
6207 * GetJobA [WINSPOOL.@]
6210 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6211 DWORD cbBuf, LPDWORD pcbNeeded)
6213 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
6216 /*****************************************************************************
6217 * GetJobW [WINSPOOL.@]
6220 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6221 DWORD cbBuf, LPDWORD pcbNeeded)
6223 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
6226 /*****************************************************************************
6227 * schedule_lpr
6229 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
6231 char *unixname, *queue, *cmd;
6232 char fmt[] = "lpr -P%s %s";
6233 DWORD len;
6235 if(!(unixname = wine_get_unix_file_name(filename)))
6236 return FALSE;
6238 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
6239 queue = HeapAlloc(GetProcessHeap(), 0, len);
6240 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
6242 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
6243 sprintf(cmd, fmt, queue, unixname);
6245 TRACE("printing with: %s\n", cmd);
6246 system(cmd);
6248 HeapFree(GetProcessHeap(), 0, cmd);
6249 HeapFree(GetProcessHeap(), 0, queue);
6250 HeapFree(GetProcessHeap(), 0, unixname);
6251 return TRUE;
6254 /*****************************************************************************
6255 * schedule_cups
6257 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
6259 #if HAVE_CUPS_CUPS_H
6260 if(pcupsPrintFile)
6262 char *unixname, *queue, *doc_titleA;
6263 DWORD len;
6264 BOOL ret;
6266 if(!(unixname = wine_get_unix_file_name(filename)))
6267 return FALSE;
6269 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
6270 queue = HeapAlloc(GetProcessHeap(), 0, len);
6271 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
6273 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
6274 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
6275 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
6277 TRACE("printing via cups\n");
6278 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
6279 HeapFree(GetProcessHeap(), 0, doc_titleA);
6280 HeapFree(GetProcessHeap(), 0, queue);
6281 HeapFree(GetProcessHeap(), 0, unixname);
6282 return ret;
6284 else
6285 #endif
6287 return schedule_lpr(printer_name, filename);
6291 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
6293 LPWSTR filename;
6295 switch(msg)
6297 case WM_INITDIALOG:
6298 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
6299 return TRUE;
6301 case WM_COMMAND:
6302 if(HIWORD(wparam) == BN_CLICKED)
6304 if(LOWORD(wparam) == IDOK)
6306 HANDLE hf;
6307 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
6308 LPWSTR *output;
6310 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
6311 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
6313 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
6315 WCHAR caption[200], message[200];
6316 int mb_ret;
6318 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
6319 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
6320 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
6321 if(mb_ret == IDCANCEL)
6323 HeapFree(GetProcessHeap(), 0, filename);
6324 return TRUE;
6327 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
6328 if(hf == INVALID_HANDLE_VALUE)
6330 WCHAR caption[200], message[200];
6332 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
6333 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
6334 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
6335 HeapFree(GetProcessHeap(), 0, filename);
6336 return TRUE;
6338 CloseHandle(hf);
6339 DeleteFileW(filename);
6340 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
6341 *output = filename;
6342 EndDialog(hwnd, IDOK);
6343 return TRUE;
6345 if(LOWORD(wparam) == IDCANCEL)
6347 EndDialog(hwnd, IDCANCEL);
6348 return TRUE;
6351 return FALSE;
6353 return FALSE;
6356 /*****************************************************************************
6357 * get_filename
6359 static BOOL get_filename(LPWSTR *filename)
6361 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
6362 file_dlg_proc, (LPARAM)filename) == IDOK;
6365 /*****************************************************************************
6366 * schedule_file
6368 static BOOL schedule_file(LPCWSTR filename)
6370 LPWSTR output = NULL;
6372 if(get_filename(&output))
6374 TRACE("copy to %s\n", debugstr_w(output));
6375 CopyFileW(filename, output, FALSE);
6376 HeapFree(GetProcessHeap(), 0, output);
6377 return TRUE;
6379 return FALSE;
6382 /*****************************************************************************
6383 * schedule_pipe
6385 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
6387 #ifdef HAVE_FORK
6388 char *unixname, *cmdA;
6389 DWORD len;
6390 int fds[2] = {-1, -1}, file_fd = -1, no_read;
6391 BOOL ret = FALSE;
6392 char buf[1024];
6394 if(!(unixname = wine_get_unix_file_name(filename)))
6395 return FALSE;
6397 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
6398 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
6399 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
6401 TRACE("printing with: %s\n", cmdA);
6403 if((file_fd = open(unixname, O_RDONLY)) == -1)
6404 goto end;
6406 if (pipe(fds))
6408 ERR("pipe() failed!\n");
6409 goto end;
6412 if (fork() == 0)
6414 close(0);
6415 dup2(fds[0], 0);
6416 close(fds[1]);
6418 /* reset signals that we previously set to SIG_IGN */
6419 signal(SIGPIPE, SIG_DFL);
6420 signal(SIGCHLD, SIG_DFL);
6422 system(cmdA);
6423 exit(0);
6426 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
6427 write(fds[1], buf, no_read);
6429 ret = TRUE;
6431 end:
6432 if(file_fd != -1) close(file_fd);
6433 if(fds[0] != -1) close(fds[0]);
6434 if(fds[1] != -1) close(fds[1]);
6436 HeapFree(GetProcessHeap(), 0, cmdA);
6437 HeapFree(GetProcessHeap(), 0, unixname);
6438 return ret;
6439 #else
6440 return FALSE;
6441 #endif
6444 /*****************************************************************************
6445 * schedule_unixfile
6447 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
6449 int in_fd, out_fd, no_read;
6450 char buf[1024];
6451 BOOL ret = FALSE;
6452 char *unixname, *outputA;
6453 DWORD len;
6455 if(!(unixname = wine_get_unix_file_name(filename)))
6456 return FALSE;
6458 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
6459 outputA = HeapAlloc(GetProcessHeap(), 0, len);
6460 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
6462 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
6463 in_fd = open(unixname, O_RDONLY);
6464 if(out_fd == -1 || in_fd == -1)
6465 goto end;
6467 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
6468 write(out_fd, buf, no_read);
6470 ret = TRUE;
6471 end:
6472 if(in_fd != -1) close(in_fd);
6473 if(out_fd != -1) close(out_fd);
6474 HeapFree(GetProcessHeap(), 0, outputA);
6475 HeapFree(GetProcessHeap(), 0, unixname);
6476 return ret;
6479 /*****************************************************************************
6480 * ScheduleJob [WINSPOOL.@]
6483 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
6485 opened_printer_t *printer;
6486 BOOL ret = FALSE;
6487 struct list *cursor, *cursor2;
6489 TRACE("(%p, %lx)\n", hPrinter, dwJobID);
6490 EnterCriticalSection(&printer_handles_cs);
6491 printer = get_opened_printer(hPrinter);
6492 if(!printer)
6493 goto end;
6495 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
6497 job_t *job = LIST_ENTRY(cursor, job_t, entry);
6498 HANDLE hf;
6500 if(job->job_id != dwJobID) continue;
6502 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
6503 if(hf != INVALID_HANDLE_VALUE)
6505 PRINTER_INFO_5W *pi5;
6506 DWORD needed;
6507 HKEY hkey;
6508 WCHAR output[1024];
6509 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
6510 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
6512 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
6513 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
6514 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
6515 TRACE("need to schedule job %ld filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
6516 debugstr_w(pi5->pPortName));
6518 output[0] = 0;
6520 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
6521 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
6523 DWORD type, count = sizeof(output);
6524 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
6525 RegCloseKey(hkey);
6527 if(output[0] == '|')
6529 schedule_pipe(output + 1, job->filename);
6531 else if(output[0])
6533 schedule_unixfile(output, job->filename);
6535 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
6537 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
6539 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
6541 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
6543 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
6545 schedule_file(job->filename);
6547 else
6549 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
6551 HeapFree(GetProcessHeap(), 0, pi5);
6552 CloseHandle(hf);
6553 DeleteFileW(job->filename);
6555 list_remove(cursor);
6556 HeapFree(GetProcessHeap(), 0, job->document_title);
6557 HeapFree(GetProcessHeap(), 0, job->filename);
6558 HeapFree(GetProcessHeap(), 0, job);
6559 ret = TRUE;
6560 break;
6562 end:
6563 LeaveCriticalSection(&printer_handles_cs);
6564 return ret;
6567 /*****************************************************************************
6568 * StartDocDlgA [WINSPOOL.@]
6570 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
6572 UNICODE_STRING usBuffer;
6573 DOCINFOW docW;
6574 LPWSTR retW;
6575 LPSTR ret = NULL;
6577 docW.cbSize = sizeof(docW);
6578 docW.lpszDocName = asciitounicode(&usBuffer, doc->lpszDocName);
6579 docW.lpszOutput = asciitounicode(&usBuffer, doc->lpszOutput);
6580 docW.lpszDatatype = asciitounicode(&usBuffer, doc->lpszDatatype);
6581 docW.fwType = doc->fwType;
6583 retW = StartDocDlgW(hPrinter, &docW);
6585 if(retW)
6587 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
6588 ret = HeapAlloc(GetProcessHeap(), 0, len);
6589 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
6590 HeapFree(GetProcessHeap(), 0, retW);
6593 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDatatype);
6594 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszOutput);
6595 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDocName);
6597 return ret;
6600 /*****************************************************************************
6601 * StartDocDlgW [WINSPOOL.@]
6603 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
6604 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
6605 * port is "FILE:". Also returns the full path if passed a relative path.
6607 * The caller should free the returned string from the process heap.
6609 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
6611 LPWSTR ret = NULL;
6612 DWORD len, attr;
6614 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
6616 PRINTER_INFO_5W *pi5;
6617 GetPrinterW(hPrinter, 5, NULL, 0, &len);
6618 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
6619 return NULL;
6620 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
6621 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
6622 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
6624 HeapFree(GetProcessHeap(), 0, pi5);
6625 return NULL;
6627 HeapFree(GetProcessHeap(), 0, pi5);
6630 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
6632 LPWSTR name;
6633 get_filename(&name);
6634 if(name)
6636 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
6638 HeapFree(GetProcessHeap(), 0, name);
6639 return NULL;
6641 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6642 GetFullPathNameW(name, len, ret, NULL);
6643 HeapFree(GetProcessHeap(), 0, name);
6645 return ret;
6648 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
6649 return NULL;
6651 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6652 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
6654 attr = GetFileAttributesW(ret);
6655 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
6657 HeapFree(GetProcessHeap(), 0, ret);
6658 ret = NULL;
6660 return ret;