winspool: Use printenv_t for GetDriverInfoFromReg.
[wine/hacks.git] / dlls / winspool.drv / info.c
blobf5ed7ef159514da110fb61a89506b54868715a2b
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, 2007 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 #endif
43 #define NONAMELESSUNION
44 #define NONAMELESSSTRUCT
45 #include "wine/library.h"
46 #include "windef.h"
47 #include "winbase.h"
48 #include "winuser.h"
49 #include "winerror.h"
50 #include "winreg.h"
51 #include "wingdi.h"
52 #include "winspool.h"
53 #include "winternl.h"
54 #include "wine/windef16.h"
55 #include "wine/unicode.h"
56 #include "wine/debug.h"
57 #include "wine/list.h"
58 #include "winnls.h"
60 #include "ddk/winsplp.h"
61 #include "wspool.h"
63 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
65 /* ############################### */
67 static CRITICAL_SECTION monitor_handles_cs;
68 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
70 0, 0, &monitor_handles_cs,
71 { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
72 0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
74 static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
77 static CRITICAL_SECTION printer_handles_cs;
78 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
80 0, 0, &printer_handles_cs,
81 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
82 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
84 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
86 /* ############################### */
88 typedef struct {
89 struct list entry;
90 LPWSTR name;
91 LPWSTR dllname;
92 PMONITORUI monitorUI;
93 LPMONITOR monitor;
94 HMODULE hdll;
95 DWORD refcount;
96 DWORD dwMonitorSize;
97 } monitor_t;
99 typedef struct {
100 DWORD job_id;
101 HANDLE hf;
102 } started_doc_t;
104 typedef struct {
105 struct list jobs;
106 LONG ref;
107 } jobqueue_t;
109 typedef struct {
110 LPWSTR name;
111 LPWSTR printername;
112 monitor_t *pm;
113 HANDLE hXcv;
114 jobqueue_t *queue;
115 started_doc_t *doc;
116 } opened_printer_t;
118 typedef struct {
119 struct list entry;
120 DWORD job_id;
121 WCHAR *filename;
122 WCHAR *document_title;
123 } job_t;
126 typedef struct {
127 LPCWSTR envname;
128 LPCWSTR subdir;
129 DWORD driverversion;
130 LPCWSTR versionregpath;
131 LPCWSTR versionsubdir;
132 } printenv_t;
134 /* ############################### */
136 static struct list monitor_handles = LIST_INIT( monitor_handles );
137 static monitor_t * pm_localport;
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 WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
185 'M','i','c','r','o','s','o','f','t','\\',
186 'W','i','n','d','o','w','s',' ','N','T','\\',
187 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
188 'P','o','r','t','s',0};
190 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
191 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
192 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
193 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
194 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
195 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
196 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
198 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
199 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
201 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
202 'i','o','n',' ','F','i','l','e',0};
203 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
204 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
205 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
206 'M','o','d','e',0};
207 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
208 'i','l','e','s',0};
209 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
210 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
211 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
212 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
213 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
214 static const WCHAR MonitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
215 static const WCHAR NameW[] = {'N','a','m','e',0};
216 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
217 static const WCHAR PortW[] = {'P','o','r','t',0};
218 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
219 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
220 's','s','o','r',0};
221 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
222 'v','e','r',0};
223 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
224 'v','e','r','D','a','t','a',0};
225 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
226 'i','l','e',0};
227 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
228 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
229 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
230 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
231 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
232 static const WCHAR emptyStringW[] = {0};
233 static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
234 static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
236 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
238 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
239 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
240 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
242 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
243 'D','o','c','u','m','e','n','t',0};
246 /******************************************************************
247 * validate the user-supplied printing-environment [internal]
249 * PARAMS
250 * env [I] PTR to Environment-String or NULL
252 * RETURNS
253 * Failure: NULL
254 * Success: PTR to printenv_t
256 * NOTES
257 * An empty string is handled the same way as NULL.
258 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
262 static const printenv_t * validate_envW(LPCWSTR env)
264 static const printenv_t env_x86 = {envname_x86W, subdir_x86W,
265 3, Version3_RegPathW, Version3_SubdirW};
266 static const printenv_t env_win40 = {envname_win40W, subdir_win40W,
267 0, emptyStringW, emptyStringW};
268 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
270 const printenv_t *result = NULL;
271 unsigned int i;
273 TRACE("testing %s\n", debugstr_w(env));
274 if (env && env[0])
276 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
278 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
280 result = all_printenv[i];
281 break;
285 if (result == NULL) {
286 FIXME("unsupported Environment: %s\n", debugstr_w(env));
287 SetLastError(ERROR_INVALID_ENVIRONMENT);
289 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
291 else
293 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
295 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
297 return result;
301 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
302 if passed a NULL string. This returns NULLs to the result.
304 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
306 if ( (src) )
308 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
309 return usBufferPtr->Buffer;
311 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
312 return NULL;
315 static LPWSTR strdupW(LPCWSTR p)
317 LPWSTR ret;
318 DWORD len;
320 if(!p) return NULL;
321 len = (strlenW(p) + 1) * sizeof(WCHAR);
322 ret = HeapAlloc(GetProcessHeap(), 0, len);
323 memcpy(ret, p, len);
324 return ret;
327 static LPSTR strdupWtoA( LPCWSTR str )
329 LPSTR ret;
330 INT len;
332 if (!str) return NULL;
333 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
334 ret = HeapAlloc( GetProcessHeap(), 0, len );
335 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
336 return ret;
339 /* Returns the number of bytes in an ansi \0\0 terminated string (multi_sz).
340 The result includes all \0s (specifically the last two). */
341 static int multi_sz_lenA(const char *str)
343 const char *ptr = str;
344 if(!str) return 0;
347 ptr += lstrlenA(ptr) + 1;
348 } while(*ptr);
350 return ptr - str + 1;
353 static void
354 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
355 char qbuf[200];
357 /* If forcing, or no profile string entry for device yet, set the entry
359 * The always change entry if not WINEPS yet is discussable.
361 if (force ||
362 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
363 !strcmp(qbuf,"*") ||
364 !strstr(qbuf,"WINEPS.DRV")
366 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
367 HKEY hkey;
369 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
370 WriteProfileStringA("windows","device",buf);
371 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
372 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
373 RegCloseKey(hkey);
375 HeapFree(GetProcessHeap(),0,buf);
379 static BOOL add_printer_driver(const char *name)
381 DRIVER_INFO_3A di3a;
383 static char driver_path[] = "wineps16",
384 data_file[] = "<datafile?>",
385 config_file[] = "wineps16",
386 help_file[] = "<helpfile?>",
387 dep_file[] = "<dependent files?>\0",
388 monitor_name[] = "<monitor name?>",
389 default_data_type[] = "RAW";
391 di3a.cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
392 di3a.pName = (char *)name;
393 di3a.pEnvironment = NULL; /* NULL means auto */
394 di3a.pDriverPath = driver_path;
395 di3a.pDataFile = data_file;
396 di3a.pConfigFile = config_file;
397 di3a.pHelpFile = help_file;
398 di3a.pDependentFiles = dep_file;
399 di3a.pMonitorName = monitor_name;
400 di3a.pDefaultDataType = default_data_type;
402 if (!AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a))
404 ERR("Failed adding driver (%d)\n", GetLastError());
405 return FALSE;
407 return TRUE;
410 #ifdef SONAME_LIBCUPS
411 static typeof(cupsGetDests) *pcupsGetDests;
412 static typeof(cupsGetPPD) *pcupsGetPPD;
413 static typeof(cupsPrintFile) *pcupsPrintFile;
414 static void *cupshandle;
416 static BOOL CUPS_LoadPrinters(void)
418 int i, nrofdests;
419 BOOL hadprinter = FALSE, haddefault = FALSE;
420 cups_dest_t *dests;
421 PRINTER_INFO_2A pinfo2a;
422 char *port,*devline;
423 HKEY hkeyPrinter, hkeyPrinters, hkey;
425 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
426 if (!cupshandle)
427 return FALSE;
428 TRACE("loaded %s\n", SONAME_LIBCUPS);
430 #define DYNCUPS(x) \
431 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
432 if (!p##x) return FALSE;
434 DYNCUPS(cupsGetPPD);
435 DYNCUPS(cupsGetDests);
436 DYNCUPS(cupsPrintFile);
437 #undef DYNCUPS
439 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
440 ERROR_SUCCESS) {
441 ERR("Can't create Printers key\n");
442 return FALSE;
445 nrofdests = pcupsGetDests(&dests);
446 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
447 for (i=0;i<nrofdests;i++) {
448 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
449 sprintf(port,"LPR:%s",dests[i].name);
450 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
451 sprintf(devline,"WINEPS.DRV,%s",port);
452 WriteProfileStringA("devices",dests[i].name,devline);
453 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
454 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
455 RegCloseKey(hkey);
457 HeapFree(GetProcessHeap(),0,devline);
459 TRACE("Printer %d: %s\n", i, dests[i].name);
460 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
461 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
462 and continue */
463 TRACE("Printer already exists\n");
464 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
465 RegCloseKey(hkeyPrinter);
466 } else {
467 static CHAR data_type[] = "RAW",
468 print_proc[] = "WinPrint",
469 comment[] = "WINEPS Printer using CUPS",
470 location[] = "<physical location of printer>",
471 params[] = "<parameters?>",
472 share_name[] = "<share name?>",
473 sep_file[] = "<sep file?>";
475 add_printer_driver(dests[i].name);
477 memset(&pinfo2a,0,sizeof(pinfo2a));
478 pinfo2a.pPrinterName = dests[i].name;
479 pinfo2a.pDatatype = data_type;
480 pinfo2a.pPrintProcessor = print_proc;
481 pinfo2a.pDriverName = dests[i].name;
482 pinfo2a.pComment = comment;
483 pinfo2a.pLocation = location;
484 pinfo2a.pPortName = port;
485 pinfo2a.pParameters = params;
486 pinfo2a.pShareName = share_name;
487 pinfo2a.pSepFile = sep_file;
489 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
490 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
491 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
494 HeapFree(GetProcessHeap(),0,port);
496 hadprinter = TRUE;
497 if (dests[i].is_default) {
498 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
499 haddefault = TRUE;
502 if (hadprinter & !haddefault)
503 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
504 RegCloseKey(hkeyPrinters);
505 return hadprinter;
507 #endif
509 static BOOL
510 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
511 PRINTER_INFO_2A pinfo2a;
512 char *e,*s,*name,*prettyname,*devname;
513 BOOL ret = FALSE, set_default = FALSE;
514 char *port,*devline,*env_default;
515 HKEY hkeyPrinter, hkeyPrinters, hkey;
517 while (isspace(*pent)) pent++;
518 s = strchr(pent,':');
519 if(s) *s='\0';
520 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
521 strcpy(name,pent);
522 if(s) {
523 *s=':';
524 pent = s;
525 } else
526 pent = "";
528 TRACE("name=%s entry=%s\n",name, pent);
530 if(ispunct(*name)) { /* a tc entry, not a real printer */
531 TRACE("skipping tc entry\n");
532 goto end;
535 if(strstr(pent,":server")) { /* server only version so skip */
536 TRACE("skipping server entry\n");
537 goto end;
540 /* Determine whether this is a postscript printer. */
542 ret = TRUE;
543 env_default = getenv("PRINTER");
544 prettyname = name;
545 /* Get longest name, usually the one at the right for later display. */
546 while((s=strchr(prettyname,'|'))) {
547 *s = '\0';
548 e = s;
549 while(isspace(*--e)) *e = '\0';
550 TRACE("\t%s\n", debugstr_a(prettyname));
551 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
552 for(prettyname = s+1; isspace(*prettyname); prettyname++)
555 e = prettyname + strlen(prettyname);
556 while(isspace(*--e)) *e = '\0';
557 TRACE("\t%s\n", debugstr_a(prettyname));
558 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
560 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
561 * if it is too long, we use it as comment below. */
562 devname = prettyname;
563 if (strlen(devname)>=CCHDEVICENAME-1)
564 devname = name;
565 if (strlen(devname)>=CCHDEVICENAME-1) {
566 ret = FALSE;
567 goto end;
570 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
571 sprintf(port,"LPR:%s",name);
573 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
574 sprintf(devline,"WINEPS.DRV,%s",port);
575 WriteProfileStringA("devices",devname,devline);
576 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
577 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
578 RegCloseKey(hkey);
580 HeapFree(GetProcessHeap(),0,devline);
582 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
583 ERROR_SUCCESS) {
584 ERR("Can't create Printers key\n");
585 ret = FALSE;
586 goto end;
588 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
589 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
590 and continue */
591 TRACE("Printer already exists\n");
592 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
593 RegCloseKey(hkeyPrinter);
594 } else {
595 static CHAR data_type[] = "RAW",
596 print_proc[] = "WinPrint",
597 comment[] = "WINEPS Printer using LPR",
598 params[] = "<parameters?>",
599 share_name[] = "<share name?>",
600 sep_file[] = "<sep file?>";
602 add_printer_driver(devname);
604 memset(&pinfo2a,0,sizeof(pinfo2a));
605 pinfo2a.pPrinterName = devname;
606 pinfo2a.pDatatype = data_type;
607 pinfo2a.pPrintProcessor = print_proc;
608 pinfo2a.pDriverName = devname;
609 pinfo2a.pComment = comment;
610 pinfo2a.pLocation = prettyname;
611 pinfo2a.pPortName = port;
612 pinfo2a.pParameters = params;
613 pinfo2a.pShareName = share_name;
614 pinfo2a.pSepFile = sep_file;
616 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
617 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
618 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
621 RegCloseKey(hkeyPrinters);
623 if (isfirst || set_default)
624 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
626 HeapFree(GetProcessHeap(), 0, port);
627 end:
628 HeapFree(GetProcessHeap(), 0, name);
629 return ret;
632 static BOOL
633 PRINTCAP_LoadPrinters(void) {
634 BOOL hadprinter = FALSE;
635 char buf[200];
636 FILE *f;
637 char *pent = NULL;
638 BOOL had_bash = FALSE;
640 f = fopen("/etc/printcap","r");
641 if (!f)
642 return FALSE;
644 while(fgets(buf,sizeof(buf),f)) {
645 char *start, *end;
647 end=strchr(buf,'\n');
648 if (end) *end='\0';
650 start = buf;
651 while(isspace(*start)) start++;
652 if(*start == '#' || *start == '\0')
653 continue;
655 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
656 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
657 HeapFree(GetProcessHeap(),0,pent);
658 pent = NULL;
661 if (end && *--end == '\\') {
662 *end = '\0';
663 had_bash = TRUE;
664 } else
665 had_bash = FALSE;
667 if (pent) {
668 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
669 strcat(pent,start);
670 } else {
671 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
672 strcpy(pent,start);
676 if(pent) {
677 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
678 HeapFree(GetProcessHeap(),0,pent);
680 fclose(f);
681 return hadprinter;
684 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
686 if (value)
687 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
688 (lstrlenW(value) + 1) * sizeof(WCHAR));
689 else
690 return ERROR_FILE_NOT_FOUND;
693 /*****************************************************************************
694 * enumerate the local monitors (INTERNAL)
696 * returns the needed size (in bytes) for pMonitors
697 * and *lpreturned is set to number of entries returned in pMonitors
700 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
702 HKEY hroot = NULL;
703 HKEY hentry = NULL;
704 LPWSTR ptr;
705 LPMONITOR_INFO_2W mi;
706 WCHAR buffer[MAX_PATH];
707 WCHAR dllname[MAX_PATH];
708 DWORD dllsize;
709 DWORD len;
710 DWORD index = 0;
711 DWORD needed = 0;
712 DWORD numentries;
713 DWORD entrysize;
715 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
717 numentries = *lpreturned; /* this is 0, when we scan the registry */
718 len = entrysize * numentries;
719 ptr = (LPWSTR) &pMonitors[len];
721 numentries = 0;
722 len = sizeof(buffer);
723 buffer[0] = '\0';
725 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
726 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
727 /* Scan all Monitor-Registry-Keys */
728 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
729 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
730 dllsize = sizeof(dllname);
731 dllname[0] = '\0';
733 /* The Monitor must have a Driver-DLL */
734 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
735 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
736 /* We found a valid DLL for this Monitor. */
737 TRACE("using Driver: %s\n", debugstr_w(dllname));
739 RegCloseKey(hentry);
742 /* Windows returns only Port-Monitors here, but to simplify our code,
743 we do no filtering for Language-Monitors */
744 if (dllname[0]) {
745 numentries++;
746 needed += entrysize;
747 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
748 if (level > 1) {
749 /* we install and return only monitors for "Windows NT x86" */
750 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
751 needed += dllsize;
754 /* required size is calculated. Now fill the user-buffer */
755 if (pMonitors && (cbBuf >= needed)){
756 mi = (LPMONITOR_INFO_2W) pMonitors;
757 pMonitors += entrysize;
759 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
760 mi->pName = ptr;
761 lstrcpyW(ptr, buffer); /* Name of the Monitor */
762 ptr += (len+1); /* len is lstrlenW(monitorname) */
763 if (level > 1) {
764 mi->pEnvironment = ptr;
765 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
766 ptr += (lstrlenW(envname_x86W)+1);
768 mi->pDLLName = ptr;
769 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
770 ptr += (dllsize / sizeof(WCHAR));
774 index++;
775 len = sizeof(buffer);
776 buffer[0] = '\0';
778 RegCloseKey(hroot);
780 *lpreturned = numentries;
781 TRACE("need %d byte for %d entries\n", needed, numentries);
782 return needed;
785 /******************************************************************
786 * monitor_unload [internal]
788 * release a printmonitor and unload it from memory, when needed
791 static void monitor_unload(monitor_t * pm)
793 if (pm == NULL) return;
794 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
796 EnterCriticalSection(&monitor_handles_cs);
798 if (pm->refcount) pm->refcount--;
800 if (pm->refcount == 0) {
801 list_remove(&pm->entry);
802 FreeLibrary(pm->hdll);
803 HeapFree(GetProcessHeap(), 0, pm->name);
804 HeapFree(GetProcessHeap(), 0, pm->dllname);
805 HeapFree(GetProcessHeap(), 0, pm);
807 LeaveCriticalSection(&monitor_handles_cs);
810 /******************************************************************
811 * monitor_unloadall [internal]
813 * release all printmonitors and unload them from memory, when needed
816 static void monitor_unloadall(void)
818 monitor_t * pm;
819 monitor_t * next;
821 EnterCriticalSection(&monitor_handles_cs);
822 /* iterate through the list, with safety against removal */
823 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
825 monitor_unload(pm);
827 LeaveCriticalSection(&monitor_handles_cs);
830 /******************************************************************
831 * monitor_load [internal]
833 * load a printmonitor, get the dllname from the registry, when needed
834 * initialize the monitor and dump found function-pointers
836 * On failure, SetLastError() is called and NULL is returned
839 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
841 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
842 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
843 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
844 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
845 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
847 monitor_t * pm = NULL;
848 monitor_t * cursor;
849 LPWSTR regroot = NULL;
850 LPWSTR driver = dllname;
852 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
853 /* Is the Monitor already loaded? */
854 EnterCriticalSection(&monitor_handles_cs);
856 if (name) {
857 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
859 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
860 pm = cursor;
861 break;
866 if (pm == NULL) {
867 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
868 if (pm == NULL) goto cleanup;
869 list_add_tail(&monitor_handles, &pm->entry);
871 pm->refcount++;
873 if (pm->name == NULL) {
874 /* Load the monitor */
875 LPMONITOREX pmonitorEx;
876 DWORD len;
878 if (name) {
879 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
880 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
883 if (regroot) {
884 lstrcpyW(regroot, MonitorsW);
885 lstrcatW(regroot, name);
886 /* Get the Driver from the Registry */
887 if (driver == NULL) {
888 HKEY hroot;
889 DWORD namesize;
890 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
891 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
892 &namesize) == ERROR_SUCCESS) {
893 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
894 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
896 RegCloseKey(hroot);
901 pm->name = strdupW(name);
902 pm->dllname = strdupW(driver);
904 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
905 monitor_unload(pm);
906 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
907 pm = NULL;
908 goto cleanup;
911 pm->hdll = LoadLibraryW(driver);
912 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
914 if (pm->hdll == NULL) {
915 monitor_unload(pm);
916 SetLastError(ERROR_MOD_NOT_FOUND);
917 pm = NULL;
918 goto cleanup;
921 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
922 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
923 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
924 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
925 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
928 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
929 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
930 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
931 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
932 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
934 if (pInitializePrintMonitorUI != NULL) {
935 pm->monitorUI = pInitializePrintMonitorUI();
936 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
937 if (pm->monitorUI) {
938 TRACE( "0x%08x: dwMonitorSize (%d)\n",
939 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
944 if (pInitializePrintMonitor && regroot) {
945 pmonitorEx = pInitializePrintMonitor(regroot);
946 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
947 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
949 if (pmonitorEx) {
950 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
951 pm->monitor = &(pmonitorEx->Monitor);
955 if (pm->monitor) {
956 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
960 if (!pm->monitor && regroot) {
961 if (pInitializePrintMonitor2 != NULL) {
962 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
964 if (pInitializeMonitorEx != NULL) {
965 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
967 if (pInitializeMonitor != NULL) {
968 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
971 if (!pm->monitor && !pm->monitorUI) {
972 monitor_unload(pm);
973 SetLastError(ERROR_PROC_NOT_FOUND);
974 pm = NULL;
977 cleanup:
978 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
979 pm->refcount++;
980 pm_localport = pm;
982 LeaveCriticalSection(&monitor_handles_cs);
983 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
984 HeapFree(GetProcessHeap(), 0, regroot);
985 TRACE("=> %p\n", pm);
986 return pm;
989 /******************************************************************
990 * monitor_loadall [internal]
992 * Load all registered monitors
995 static DWORD monitor_loadall(void)
997 monitor_t * pm;
998 DWORD registered = 0;
999 DWORD loaded = 0;
1000 HKEY hmonitors;
1001 WCHAR buffer[MAX_PATH];
1002 DWORD id = 0;
1004 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hmonitors) == ERROR_SUCCESS) {
1005 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
1006 NULL, NULL, NULL, NULL, NULL);
1008 TRACE("%d monitors registered\n", registered);
1010 EnterCriticalSection(&monitor_handles_cs);
1011 while (id < registered) {
1012 buffer[0] = '\0';
1013 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
1014 pm = monitor_load(buffer, NULL);
1015 if (pm) loaded++;
1016 id++;
1018 LeaveCriticalSection(&monitor_handles_cs);
1019 RegCloseKey(hmonitors);
1021 TRACE("%d monitors loaded\n", loaded);
1022 return loaded;
1025 /******************************************************************
1026 * monitor_loadui [internal]
1028 * load the userinterface-dll for a given portmonitor
1030 * On failure, NULL is returned
1033 static monitor_t * monitor_loadui(monitor_t * pm)
1035 monitor_t * pui = NULL;
1036 LPWSTR buffer[MAX_PATH];
1037 HANDLE hXcv;
1038 DWORD len;
1039 DWORD res;
1041 if (pm == NULL) return NULL;
1042 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
1044 /* Try the Portmonitor first; works for many monitors */
1045 if (pm->monitorUI) {
1046 EnterCriticalSection(&monitor_handles_cs);
1047 pm->refcount++;
1048 LeaveCriticalSection(&monitor_handles_cs);
1049 return pm;
1052 /* query the userinterface-dllname from the Portmonitor */
1053 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
1054 /* building (",XcvMonitor %s",pm->name) not needed yet */
1055 res = pm->monitor->pfnXcvOpenPort(emptyStringW, SERVER_ACCESS_ADMINISTER, &hXcv);
1056 TRACE("got %u with %p\n", res, hXcv);
1057 if (res) {
1058 res = pm->monitor->pfnXcvDataPort(hXcv, MonitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
1059 TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
1060 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
1061 pm->monitor->pfnXcvClosePort(hXcv);
1064 return pui;
1068 /******************************************************************
1069 * monitor_load_by_port [internal]
1071 * load a printmonitor for a given port
1073 * On failure, NULL is returned
1076 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1078 HKEY hroot;
1079 HKEY hport;
1080 LPWSTR buffer;
1081 monitor_t * pm = NULL;
1082 DWORD registered = 0;
1083 DWORD id = 0;
1084 DWORD len;
1086 TRACE("(%s)\n", debugstr_w(portname));
1088 /* Try the Local Monitor first */
1089 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1090 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1091 /* found the portname */
1092 RegCloseKey(hroot);
1093 return monitor_load(LocalPortW, NULL);
1095 RegCloseKey(hroot);
1098 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1099 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1100 if (buffer == NULL) return NULL;
1102 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1103 EnterCriticalSection(&monitor_handles_cs);
1104 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1106 while ((pm == NULL) && (id < registered)) {
1107 buffer[0] = '\0';
1108 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1109 TRACE("testing %s\n", debugstr_w(buffer));
1110 len = lstrlenW(buffer);
1111 lstrcatW(buffer, bs_Ports_bsW);
1112 lstrcatW(buffer, portname);
1113 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1114 RegCloseKey(hport);
1115 buffer[len] = '\0'; /* use only the Monitor-Name */
1116 pm = monitor_load(buffer, NULL);
1118 id++;
1120 LeaveCriticalSection(&monitor_handles_cs);
1121 RegCloseKey(hroot);
1123 HeapFree(GetProcessHeap(), 0, buffer);
1124 return pm;
1127 /******************************************************************
1128 * enumerate the local Ports from all loaded monitors (internal)
1130 * returns the needed size (in bytes) for pPorts
1131 * and *lpreturned is set to number of entries returned in pPorts
1134 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
1136 monitor_t * pm;
1137 LPWSTR ptr;
1138 LPPORT_INFO_2W cache;
1139 LPPORT_INFO_2W out;
1140 LPBYTE pi_buffer = NULL;
1141 DWORD pi_allocated = 0;
1142 DWORD pi_needed;
1143 DWORD pi_index;
1144 DWORD pi_returned;
1145 DWORD res;
1146 DWORD outindex = 0;
1147 DWORD needed;
1148 DWORD numentries;
1149 DWORD entrysize;
1152 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
1153 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
1155 numentries = *lpreturned; /* this is 0, when we scan the registry */
1156 needed = entrysize * numentries;
1157 ptr = (LPWSTR) &pPorts[needed];
1159 numentries = 0;
1160 needed = 0;
1162 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1164 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
1165 pi_needed = 0;
1166 pi_returned = 0;
1167 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1168 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
1169 /* Do not use HeapReAlloc (we do not need the old data in the buffer) */
1170 HeapFree(GetProcessHeap(), 0, pi_buffer);
1171 pi_buffer = HeapAlloc(GetProcessHeap(), 0, pi_needed);
1172 pi_allocated = (pi_buffer) ? pi_needed : 0;
1173 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1175 TRACE( "(%s) got %d with %d (need %d byte for %d entries)\n",
1176 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
1178 numentries += pi_returned;
1179 needed += pi_needed;
1181 /* fill the output-buffer (pPorts), if we have one */
1182 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
1183 pi_index = 0;
1184 while (pi_returned > pi_index) {
1185 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
1186 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
1187 out->pPortName = ptr;
1188 lstrcpyW(ptr, cache->pPortName);
1189 ptr += (lstrlenW(ptr)+1);
1190 if (level > 1) {
1191 out->pMonitorName = ptr;
1192 lstrcpyW(ptr, cache->pMonitorName);
1193 ptr += (lstrlenW(ptr)+1);
1195 out->pDescription = ptr;
1196 lstrcpyW(ptr, cache->pDescription);
1197 ptr += (lstrlenW(ptr)+1);
1198 out->fPortType = cache->fPortType;
1199 out->Reserved = cache->Reserved;
1201 pi_index++;
1202 outindex++;
1207 /* the temporary portinfo-buffer is no longer needed */
1208 HeapFree(GetProcessHeap(), 0, pi_buffer);
1210 *lpreturned = numentries;
1211 TRACE("need %d byte for %d entries\n", needed, numentries);
1212 return needed;
1215 /******************************************************************
1216 * get_servername_from_name (internal)
1218 * for an external server, a copy of the serverpart from the full name is returned
1221 static LPWSTR get_servername_from_name(LPCWSTR name)
1223 LPWSTR server;
1224 LPWSTR ptr;
1225 WCHAR buffer[MAX_PATH];
1226 DWORD len;
1228 if (name == NULL) return NULL;
1229 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1231 server = strdupW(&name[2]); /* skip over both backslash */
1232 if (server == NULL) return NULL;
1234 /* strip '\' and the printername */
1235 ptr = strchrW(server, '\\');
1236 if (ptr) ptr[0] = '\0';
1238 TRACE("found %s\n", debugstr_w(server));
1240 len = sizeof(buffer)/sizeof(buffer[0]);
1241 if (GetComputerNameW(buffer, &len)) {
1242 if (lstrcmpW(buffer, server) == 0) {
1243 /* The requested Servername is our computername */
1244 HeapFree(GetProcessHeap(), 0, server);
1245 return NULL;
1248 return server;
1251 /******************************************************************
1252 * get_basename_from_name (internal)
1254 * skip over the serverpart from the full name
1257 static LPCWSTR get_basename_from_name(LPCWSTR name)
1259 if (name == NULL) return NULL;
1260 if ((name[0] == '\\') && (name[1] == '\\')) {
1261 /* skip over the servername and search for the following '\' */
1262 name = strchrW(&name[2], '\\');
1263 if ((name) && (name[1])) {
1264 /* found a separator ('\') followed by a name:
1265 skip over the separator and return the rest */
1266 name++;
1268 else
1270 /* no basename present (we found only a servername) */
1271 return NULL;
1274 return name;
1277 /******************************************************************
1278 * get_opened_printer_entry
1279 * Get the first place empty in the opened printer table
1281 * ToDo:
1282 * - pDefault is ignored
1284 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1286 UINT_PTR handle = nb_printer_handles, i;
1287 jobqueue_t *queue = NULL;
1288 opened_printer_t *printer = NULL;
1289 LPWSTR servername;
1290 LPCWSTR printername;
1291 HKEY hkeyPrinters;
1292 HKEY hkeyPrinter;
1293 DWORD len;
1295 servername = get_servername_from_name(name);
1296 if (servername) {
1297 FIXME("server %s not supported\n", debugstr_w(servername));
1298 HeapFree(GetProcessHeap(), 0, servername);
1299 SetLastError(ERROR_INVALID_PRINTER_NAME);
1300 return NULL;
1303 printername = get_basename_from_name(name);
1304 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1306 /* an empty printername is invalid */
1307 if (printername && (!printername[0])) {
1308 SetLastError(ERROR_INVALID_PARAMETER);
1309 return NULL;
1312 EnterCriticalSection(&printer_handles_cs);
1314 for (i = 0; i < nb_printer_handles; i++)
1316 if (!printer_handles[i])
1318 if(handle == nb_printer_handles)
1319 handle = i;
1321 else
1323 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1324 queue = printer_handles[i]->queue;
1328 if (handle >= nb_printer_handles)
1330 opened_printer_t **new_array;
1331 if (printer_handles)
1332 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1333 (nb_printer_handles + 16) * sizeof(*new_array) );
1334 else
1335 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1336 (nb_printer_handles + 16) * sizeof(*new_array) );
1338 if (!new_array)
1340 handle = 0;
1341 goto end;
1343 printer_handles = new_array;
1344 nb_printer_handles += 16;
1347 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1349 handle = 0;
1350 goto end;
1354 /* clone the base name. This is NULL for the printserver */
1355 printer->printername = strdupW(printername);
1357 /* clone the full name */
1358 printer->name = strdupW(name);
1359 if (name && (!printer->name)) {
1360 handle = 0;
1361 goto end;
1364 if (printername) {
1365 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1366 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1367 /* OpenPrinter(",XcvMonitor " detected */
1368 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1369 printer->pm = monitor_load(&printername[len], NULL);
1370 if (printer->pm == NULL) {
1371 SetLastError(ERROR_UNKNOWN_PORT);
1372 handle = 0;
1373 goto end;
1376 else
1378 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1379 if (strncmpW( printername, XcvPortW, len) == 0) {
1380 /* OpenPrinter(",XcvPort " detected */
1381 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1382 printer->pm = monitor_load_by_port(&printername[len]);
1383 if (printer->pm == NULL) {
1384 SetLastError(ERROR_UNKNOWN_PORT);
1385 handle = 0;
1386 goto end;
1391 if (printer->pm) {
1392 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1393 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1394 pDefault ? pDefault->DesiredAccess : 0,
1395 &printer->hXcv);
1397 if (printer->hXcv == NULL) {
1398 SetLastError(ERROR_INVALID_PARAMETER);
1399 handle = 0;
1400 goto end;
1403 else
1405 /* Does the Printer exist? */
1406 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1407 ERR("Can't create Printers key\n");
1408 handle = 0;
1409 goto end;
1411 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1412 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1413 RegCloseKey(hkeyPrinters);
1414 SetLastError(ERROR_INVALID_PRINTER_NAME);
1415 handle = 0;
1416 goto end;
1418 RegCloseKey(hkeyPrinter);
1419 RegCloseKey(hkeyPrinters);
1422 else
1424 TRACE("using the local printserver\n");
1427 if(queue)
1428 printer->queue = queue;
1429 else
1431 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1432 if (!printer->queue) {
1433 handle = 0;
1434 goto end;
1436 list_init(&printer->queue->jobs);
1437 printer->queue->ref = 0;
1439 InterlockedIncrement(&printer->queue->ref);
1441 printer_handles[handle] = printer;
1442 handle++;
1443 end:
1444 LeaveCriticalSection(&printer_handles_cs);
1445 if (!handle && printer) {
1446 /* Something failed: Free all resources */
1447 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1448 monitor_unload(printer->pm);
1449 HeapFree(GetProcessHeap(), 0, printer->printername);
1450 HeapFree(GetProcessHeap(), 0, printer->name);
1451 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1452 HeapFree(GetProcessHeap(), 0, printer);
1455 return (HANDLE)handle;
1458 /******************************************************************
1459 * get_opened_printer
1460 * Get the pointer to the opened printer referred by the handle
1462 static opened_printer_t *get_opened_printer(HANDLE hprn)
1464 UINT_PTR idx = (UINT_PTR)hprn;
1465 opened_printer_t *ret = NULL;
1467 EnterCriticalSection(&printer_handles_cs);
1469 if ((idx <= 0) || (idx > nb_printer_handles))
1470 goto end;
1472 ret = printer_handles[idx - 1];
1473 end:
1474 LeaveCriticalSection(&printer_handles_cs);
1475 return ret;
1478 /******************************************************************
1479 * get_opened_printer_name
1480 * Get the pointer to the opened printer name referred by the handle
1482 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1484 opened_printer_t *printer = get_opened_printer(hprn);
1485 if(!printer) return NULL;
1486 return printer->name;
1489 /******************************************************************
1490 * WINSPOOL_GetOpenedPrinterRegKey
1493 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1495 LPCWSTR name = get_opened_printer_name(hPrinter);
1496 DWORD ret;
1497 HKEY hkeyPrinters;
1499 if(!name) return ERROR_INVALID_HANDLE;
1501 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1502 ERROR_SUCCESS)
1503 return ret;
1505 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1507 ERR("Can't find opened printer %s in registry\n",
1508 debugstr_w(name));
1509 RegCloseKey(hkeyPrinters);
1510 return ERROR_INVALID_PRINTER_NAME; /* ? */
1512 RegCloseKey(hkeyPrinters);
1513 return ERROR_SUCCESS;
1516 void WINSPOOL_LoadSystemPrinters(void)
1518 HKEY hkey, hkeyPrinters;
1519 HANDLE hprn;
1520 DWORD needed, num, i;
1521 WCHAR PrinterName[256];
1522 BOOL done = FALSE;
1524 /* This ensures that all printer entries have a valid Name value. If causes
1525 problems later if they don't. If one is found to be missed we create one
1526 and set it equal to the name of the key */
1527 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1528 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1529 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1530 for(i = 0; i < num; i++) {
1531 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
1532 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1533 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1534 set_reg_szW(hkey, NameW, PrinterName);
1536 RegCloseKey(hkey);
1541 RegCloseKey(hkeyPrinters);
1544 /* We want to avoid calling AddPrinter on printers as much as
1545 possible, because on cups printers this will (eventually) lead
1546 to a call to cupsGetPPD which takes forever, even with non-cups
1547 printers AddPrinter takes a while. So we'll tag all printers that
1548 were automatically added last time around, if they still exist
1549 we'll leave them be otherwise we'll delete them. */
1550 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1551 if(needed) {
1552 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1553 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1554 for(i = 0; i < num; i++) {
1555 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1556 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1557 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1558 DWORD dw = 1;
1559 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1560 RegCloseKey(hkey);
1562 ClosePrinter(hprn);
1567 HeapFree(GetProcessHeap(), 0, pi);
1571 #ifdef SONAME_LIBCUPS
1572 done = CUPS_LoadPrinters();
1573 #endif
1575 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1576 PRINTCAP_LoadPrinters();
1578 /* Now enumerate the list again and delete any printers that a still tagged */
1579 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1580 if(needed) {
1581 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1582 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1583 for(i = 0; i < num; i++) {
1584 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1585 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1586 BOOL delete_driver = FALSE;
1587 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1588 DWORD dw, type, size = sizeof(dw);
1589 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1590 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1591 DeletePrinter(hprn);
1592 delete_driver = TRUE;
1594 RegCloseKey(hkey);
1596 ClosePrinter(hprn);
1597 if(delete_driver)
1598 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1603 HeapFree(GetProcessHeap(), 0, pi);
1606 return;
1610 /******************************************************************
1611 * get_job
1613 * Get the pointer to the specified job.
1614 * Should hold the printer_handles_cs before calling.
1616 static job_t *get_job(HANDLE hprn, DWORD JobId)
1618 opened_printer_t *printer = get_opened_printer(hprn);
1619 job_t *job;
1621 if(!printer) return NULL;
1622 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1624 if(job->job_id == JobId)
1625 return job;
1627 return NULL;
1630 /***********************************************************
1631 * DEVMODEcpyAtoW
1633 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1635 BOOL Formname;
1636 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1637 DWORD size;
1639 Formname = (dmA->dmSize > off_formname);
1640 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1641 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1642 dmW->dmDeviceName, CCHDEVICENAME);
1643 if(!Formname) {
1644 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1645 dmA->dmSize - CCHDEVICENAME);
1646 } else {
1647 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1648 off_formname - CCHDEVICENAME);
1649 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1650 dmW->dmFormName, CCHFORMNAME);
1651 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1652 (off_formname + CCHFORMNAME));
1654 dmW->dmSize = size;
1655 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1656 dmA->dmDriverExtra);
1657 return dmW;
1660 /***********************************************************
1661 * DEVMODEdupWtoA
1662 * Creates an ascii copy of supplied devmode on heap
1664 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
1666 LPDEVMODEA dmA;
1667 DWORD size;
1668 BOOL Formname;
1669 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
1671 if(!dmW) return NULL;
1672 Formname = (dmW->dmSize > off_formname);
1673 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
1674 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1675 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1676 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1677 if(!Formname) {
1678 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1679 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
1680 } else {
1681 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1682 off_formname - CCHDEVICENAME * sizeof(WCHAR));
1683 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1684 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1685 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
1686 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
1688 dmA->dmSize = size;
1689 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
1690 dmW->dmDriverExtra);
1691 return dmA;
1694 /***********************************************************
1695 * PRINTER_INFO_2AtoW
1696 * Creates a unicode copy of PRINTER_INFO_2A on heap
1698 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1700 LPPRINTER_INFO_2W piW;
1701 UNICODE_STRING usBuffer;
1703 if(!piA) return NULL;
1704 piW = HeapAlloc(heap, 0, sizeof(*piW));
1705 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1707 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1708 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1709 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1710 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1711 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1712 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1713 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1714 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1715 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1716 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1717 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1718 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1719 return piW;
1722 /***********************************************************
1723 * FREE_PRINTER_INFO_2W
1724 * Free PRINTER_INFO_2W and all strings
1726 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1728 if(!piW) return;
1730 HeapFree(heap,0,piW->pServerName);
1731 HeapFree(heap,0,piW->pPrinterName);
1732 HeapFree(heap,0,piW->pShareName);
1733 HeapFree(heap,0,piW->pPortName);
1734 HeapFree(heap,0,piW->pDriverName);
1735 HeapFree(heap,0,piW->pComment);
1736 HeapFree(heap,0,piW->pLocation);
1737 HeapFree(heap,0,piW->pDevMode);
1738 HeapFree(heap,0,piW->pSepFile);
1739 HeapFree(heap,0,piW->pPrintProcessor);
1740 HeapFree(heap,0,piW->pDatatype);
1741 HeapFree(heap,0,piW->pParameters);
1742 HeapFree(heap,0,piW);
1743 return;
1746 /******************************************************************
1747 * DeviceCapabilities [WINSPOOL.@]
1748 * DeviceCapabilitiesA [WINSPOOL.@]
1751 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1752 LPSTR pOutput, LPDEVMODEA lpdm)
1754 INT ret;
1756 if (!GDI_CallDeviceCapabilities16)
1758 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1759 (LPCSTR)104 );
1760 if (!GDI_CallDeviceCapabilities16) return -1;
1762 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1764 /* If DC_PAPERSIZE map POINT16s to POINTs */
1765 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1766 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1767 POINT *pt = (POINT *)pOutput;
1768 INT i;
1769 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1770 for(i = 0; i < ret; i++, pt++)
1772 pt->x = tmp[i].x;
1773 pt->y = tmp[i].y;
1775 HeapFree( GetProcessHeap(), 0, tmp );
1777 return ret;
1781 /*****************************************************************************
1782 * DeviceCapabilitiesW [WINSPOOL.@]
1784 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1787 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1788 WORD fwCapability, LPWSTR pOutput,
1789 const DEVMODEW *pDevMode)
1791 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
1792 LPSTR pDeviceA = strdupWtoA(pDevice);
1793 LPSTR pPortA = strdupWtoA(pPort);
1794 INT ret;
1796 if(pOutput && (fwCapability == DC_BINNAMES ||
1797 fwCapability == DC_FILEDEPENDENCIES ||
1798 fwCapability == DC_PAPERNAMES)) {
1799 /* These need A -> W translation */
1800 INT size = 0, i;
1801 LPSTR pOutputA;
1802 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1803 dmA);
1804 if(ret == -1)
1805 return ret;
1806 switch(fwCapability) {
1807 case DC_BINNAMES:
1808 size = 24;
1809 break;
1810 case DC_PAPERNAMES:
1811 case DC_FILEDEPENDENCIES:
1812 size = 64;
1813 break;
1815 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1816 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1817 dmA);
1818 for(i = 0; i < ret; i++)
1819 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1820 pOutput + (i * size), size);
1821 HeapFree(GetProcessHeap(), 0, pOutputA);
1822 } else {
1823 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1824 (LPSTR)pOutput, dmA);
1826 HeapFree(GetProcessHeap(),0,pPortA);
1827 HeapFree(GetProcessHeap(),0,pDeviceA);
1828 HeapFree(GetProcessHeap(),0,dmA);
1829 return ret;
1832 /******************************************************************
1833 * DocumentPropertiesA [WINSPOOL.@]
1835 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1837 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1838 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1839 LPDEVMODEA pDevModeInput,DWORD fMode )
1841 LPSTR lpName = pDeviceName;
1842 static CHAR port[] = "LPT1:";
1843 LONG ret;
1845 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1846 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1849 if(!pDeviceName) {
1850 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1851 if(!lpNameW) {
1852 ERR("no name from hPrinter?\n");
1853 SetLastError(ERROR_INVALID_HANDLE);
1854 return -1;
1856 lpName = strdupWtoA(lpNameW);
1859 if (!GDI_CallExtDeviceMode16)
1861 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1862 (LPCSTR)102 );
1863 if (!GDI_CallExtDeviceMode16) {
1864 ERR("No CallExtDeviceMode16?\n");
1865 return -1;
1868 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1869 pDevModeInput, NULL, fMode);
1871 if(!pDeviceName)
1872 HeapFree(GetProcessHeap(),0,lpName);
1873 return ret;
1877 /*****************************************************************************
1878 * DocumentPropertiesW (WINSPOOL.@)
1880 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1882 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1883 LPWSTR pDeviceName,
1884 LPDEVMODEW pDevModeOutput,
1885 LPDEVMODEW pDevModeInput, DWORD fMode)
1888 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1889 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1890 LPDEVMODEA pDevModeOutputA = NULL;
1891 LONG ret;
1893 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1894 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1895 fMode);
1896 if(pDevModeOutput) {
1897 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1898 if(ret < 0) return ret;
1899 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1901 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1902 pDevModeInputA, fMode);
1903 if(pDevModeOutput) {
1904 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1905 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1907 if(fMode == 0 && ret > 0)
1908 ret += (CCHDEVICENAME + CCHFORMNAME);
1909 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1910 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1911 return ret;
1914 /******************************************************************
1915 * OpenPrinterA [WINSPOOL.@]
1917 * See OpenPrinterW.
1920 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1921 LPPRINTER_DEFAULTSA pDefault)
1923 UNICODE_STRING lpPrinterNameW;
1924 UNICODE_STRING usBuffer;
1925 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1926 PWSTR pwstrPrinterNameW;
1927 BOOL ret;
1929 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1931 if(pDefault) {
1932 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1933 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1934 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1935 pDefaultW = &DefaultW;
1937 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1938 if(pDefault) {
1939 RtlFreeUnicodeString(&usBuffer);
1940 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1942 RtlFreeUnicodeString(&lpPrinterNameW);
1943 return ret;
1946 /******************************************************************
1947 * OpenPrinterW [WINSPOOL.@]
1949 * Open a Printer / Printserver or a Printer-Object
1951 * PARAMS
1952 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1953 * phPrinter [O] The resulting Handle is stored here
1954 * pDefault [I] PTR to Default Printer Settings or NULL
1956 * RETURNS
1957 * Success: TRUE
1958 * Failure: FALSE
1960 * NOTES
1961 * lpPrinterName is one of:
1962 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1963 *| Printer: "PrinterName"
1964 *| Printer-Object: "PrinterName,Job xxx"
1965 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1966 *| XcvPort: "Servername,XcvPort PortName"
1968 * BUGS
1969 *| Printer-Object not supported
1970 *| pDefaults is ignored
1973 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1976 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1977 if (pDefault) {
1978 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1979 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1982 if(!phPrinter) {
1983 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1984 SetLastError(ERROR_INVALID_PARAMETER);
1985 return FALSE;
1988 /* Get the unique handle of the printer or Printserver */
1989 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1990 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1991 return (*phPrinter != 0);
1994 /******************************************************************
1995 * AddMonitorA [WINSPOOL.@]
1997 * See AddMonitorW.
2000 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2002 LPWSTR nameW = NULL;
2003 INT len;
2004 BOOL res;
2005 LPMONITOR_INFO_2A mi2a;
2006 MONITOR_INFO_2W mi2w;
2008 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2009 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2010 mi2a ? debugstr_a(mi2a->pName) : NULL,
2011 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
2012 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
2014 if (Level != 2) {
2015 SetLastError(ERROR_INVALID_LEVEL);
2016 return FALSE;
2019 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2020 if (mi2a == NULL) {
2021 return FALSE;
2024 if (pName) {
2025 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2026 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2027 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2030 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2031 if (mi2a->pName) {
2032 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2033 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2034 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2036 if (mi2a->pEnvironment) {
2037 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2038 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2039 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2041 if (mi2a->pDLLName) {
2042 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2043 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2044 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2047 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2049 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2050 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2051 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2053 HeapFree(GetProcessHeap(), 0, nameW);
2054 return (res);
2057 /******************************************************************************
2058 * AddMonitorW [WINSPOOL.@]
2060 * Install a Printmonitor
2062 * PARAMS
2063 * pName [I] Servername or NULL (local Computer)
2064 * Level [I] Structure-Level (Must be 2)
2065 * pMonitors [I] PTR to MONITOR_INFO_2
2067 * RETURNS
2068 * Success: TRUE
2069 * Failure: FALSE
2071 * NOTES
2072 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2075 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2077 monitor_t * pm = NULL;
2078 LPMONITOR_INFO_2W mi2w;
2079 HKEY hroot = NULL;
2080 HKEY hentry = NULL;
2081 DWORD disposition;
2082 BOOL res = FALSE;
2084 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2085 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2086 mi2w ? debugstr_w(mi2w->pName) : NULL,
2087 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
2088 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
2090 if (Level != 2) {
2091 SetLastError(ERROR_INVALID_LEVEL);
2092 return FALSE;
2095 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2096 if (mi2w == NULL) {
2097 return FALSE;
2100 if (pName && (pName[0])) {
2101 FIXME("for server %s not implemented\n", debugstr_w(pName));
2102 SetLastError(ERROR_ACCESS_DENIED);
2103 return FALSE;
2107 if (!mi2w->pName || (! mi2w->pName[0])) {
2108 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
2109 SetLastError(ERROR_INVALID_PARAMETER);
2110 return FALSE;
2112 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
2113 WARN("Environment %s requested (we support only %s)\n",
2114 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
2115 SetLastError(ERROR_INVALID_ENVIRONMENT);
2116 return FALSE;
2119 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
2120 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
2121 SetLastError(ERROR_INVALID_PARAMETER);
2122 return FALSE;
2125 /* Load and initialize the monitor. SetLastError() is called on failure */
2126 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
2127 return FALSE;
2129 monitor_unload(pm);
2131 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2132 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2133 return FALSE;
2136 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
2137 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
2138 &disposition) == ERROR_SUCCESS) {
2140 /* Some installers set options for the port before calling AddMonitor.
2141 We query the "Driver" entry to verify that the monitor is installed,
2142 before we return an error.
2143 When a user installs two print monitors at the same time with the
2144 same name but with a different driver DLL and a task switch comes
2145 between RegQueryValueExW and RegSetValueExW, a race condition
2146 is possible but silently ignored. */
2148 DWORD namesize = 0;
2150 if ((disposition == REG_OPENED_EXISTING_KEY) &&
2151 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
2152 &namesize) == ERROR_SUCCESS)) {
2153 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
2154 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2155 9x: ERROR_ALREADY_EXISTS (183) */
2156 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
2158 else
2160 INT len;
2161 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
2162 res = (RegSetValueExW(hentry, DriverW, 0,
2163 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
2165 RegCloseKey(hentry);
2168 RegCloseKey(hroot);
2169 return (res);
2172 /******************************************************************
2173 * DeletePrinterDriverA [WINSPOOL.@]
2176 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2178 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2181 /******************************************************************
2182 * DeletePrinterDriverW [WINSPOOL.@]
2185 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2187 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2190 /******************************************************************
2191 * DeleteMonitorA [WINSPOOL.@]
2193 * See DeleteMonitorW.
2196 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2198 LPWSTR nameW = NULL;
2199 LPWSTR EnvironmentW = NULL;
2200 LPWSTR MonitorNameW = NULL;
2201 BOOL res;
2202 INT len;
2204 if (pName) {
2205 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2206 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2207 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2210 if (pEnvironment) {
2211 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2212 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2213 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2215 if (pMonitorName) {
2216 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2217 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2218 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2221 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2223 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2224 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2225 HeapFree(GetProcessHeap(), 0, nameW);
2226 return (res);
2229 /******************************************************************
2230 * DeleteMonitorW [WINSPOOL.@]
2232 * Delete a specific Printmonitor from a Printing-Environment
2234 * PARAMS
2235 * pName [I] Servername or NULL (local Computer)
2236 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2237 * pMonitorName [I] Name of the Monitor, that should be deleted
2239 * RETURNS
2240 * Success: TRUE
2241 * Failure: FALSE
2243 * NOTES
2244 * pEnvironment is ignored in Windows for the local Computer.
2248 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2250 HKEY hroot = NULL;
2252 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2253 debugstr_w(pMonitorName));
2255 if (pName && (pName[0])) {
2256 FIXME("for server %s not implemented\n", debugstr_w(pName));
2257 SetLastError(ERROR_ACCESS_DENIED);
2258 return FALSE;
2261 /* pEnvironment is ignored in Windows for the local Computer */
2263 if (!pMonitorName || !pMonitorName[0]) {
2264 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
2265 SetLastError(ERROR_INVALID_PARAMETER);
2266 return FALSE;
2269 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2270 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2271 return FALSE;
2274 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
2275 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
2276 RegCloseKey(hroot);
2277 return TRUE;
2280 WARN("monitor %s does not exist\n", debugstr_w(pMonitorName));
2281 RegCloseKey(hroot);
2283 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2284 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
2285 return (FALSE);
2288 /******************************************************************
2289 * DeletePortA [WINSPOOL.@]
2291 * See DeletePortW.
2294 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2296 LPWSTR nameW = NULL;
2297 LPWSTR portW = NULL;
2298 INT len;
2299 DWORD res;
2301 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2303 /* convert servername to unicode */
2304 if (pName) {
2305 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2306 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2307 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2310 /* convert portname to unicode */
2311 if (pPortName) {
2312 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2313 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2314 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2317 res = DeletePortW(nameW, hWnd, portW);
2318 HeapFree(GetProcessHeap(), 0, nameW);
2319 HeapFree(GetProcessHeap(), 0, portW);
2320 return res;
2323 /******************************************************************
2324 * DeletePortW [WINSPOOL.@]
2326 * Delete a specific Port
2328 * PARAMS
2329 * pName [I] Servername or NULL (local Computer)
2330 * hWnd [I] Handle to parent Window for the Dialog-Box
2331 * pPortName [I] Name of the Port, that should be deleted
2333 * RETURNS
2334 * Success: TRUE
2335 * Failure: FALSE
2338 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2340 monitor_t * pm;
2341 monitor_t * pui;
2342 DWORD res;
2344 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2346 if (pName && pName[0]) {
2347 SetLastError(ERROR_INVALID_PARAMETER);
2348 return FALSE;
2351 if (!pPortName) {
2352 SetLastError(RPC_X_NULL_REF_POINTER);
2353 return FALSE;
2356 /* an empty Portname is Invalid */
2357 if (!pPortName[0]) {
2358 SetLastError(ERROR_NOT_SUPPORTED);
2359 return FALSE;
2362 pm = monitor_load_by_port(pPortName);
2363 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2364 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2365 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2366 TRACE("got %d with %u\n", res, GetLastError());
2368 else
2370 pui = monitor_loadui(pm);
2371 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2372 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2373 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2374 TRACE("got %d with %u\n", res, GetLastError());
2376 else
2378 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2379 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
2381 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2382 SetLastError(ERROR_NOT_SUPPORTED);
2383 res = FALSE;
2385 monitor_unload(pui);
2387 monitor_unload(pm);
2389 TRACE("returning %d with %u\n", res, GetLastError());
2390 return res;
2393 /******************************************************************************
2394 * SetPrinterW [WINSPOOL.@]
2396 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2398 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2399 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2400 return FALSE;
2403 /******************************************************************************
2404 * WritePrinter [WINSPOOL.@]
2406 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2408 opened_printer_t *printer;
2409 BOOL ret = FALSE;
2411 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2413 EnterCriticalSection(&printer_handles_cs);
2414 printer = get_opened_printer(hPrinter);
2415 if(!printer)
2417 SetLastError(ERROR_INVALID_HANDLE);
2418 goto end;
2421 if(!printer->doc)
2423 SetLastError(ERROR_SPL_NO_STARTDOC);
2424 goto end;
2427 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2428 end:
2429 LeaveCriticalSection(&printer_handles_cs);
2430 return ret;
2433 /*****************************************************************************
2434 * AddFormA [WINSPOOL.@]
2436 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2438 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2439 return 1;
2442 /*****************************************************************************
2443 * AddFormW [WINSPOOL.@]
2445 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2447 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2448 return 1;
2451 /*****************************************************************************
2452 * AddJobA [WINSPOOL.@]
2454 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2456 BOOL ret;
2457 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2458 DWORD needed;
2460 if(Level != 1) {
2461 SetLastError(ERROR_INVALID_LEVEL);
2462 return FALSE;
2465 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2467 if(ret) {
2468 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2469 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2470 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2471 if(*pcbNeeded > cbBuf) {
2472 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2473 ret = FALSE;
2474 } else {
2475 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2476 addjobA->JobId = addjobW->JobId;
2477 addjobA->Path = (char *)(addjobA + 1);
2478 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2481 return ret;
2484 /*****************************************************************************
2485 * AddJobW [WINSPOOL.@]
2487 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2489 opened_printer_t *printer;
2490 job_t *job;
2491 BOOL ret = FALSE;
2492 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2493 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2494 WCHAR path[MAX_PATH], filename[MAX_PATH];
2495 DWORD len;
2496 ADDJOB_INFO_1W *addjob;
2498 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2500 EnterCriticalSection(&printer_handles_cs);
2502 printer = get_opened_printer(hPrinter);
2504 if(!printer) {
2505 SetLastError(ERROR_INVALID_HANDLE);
2506 goto end;
2509 if(Level != 1) {
2510 SetLastError(ERROR_INVALID_LEVEL);
2511 goto end;
2514 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2515 if(!job)
2516 goto end;
2518 job->job_id = InterlockedIncrement(&next_job_id);
2520 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2521 if(path[len - 1] != '\\')
2522 path[len++] = '\\';
2523 memcpy(path + len, spool_path, sizeof(spool_path));
2524 sprintfW(filename, fmtW, path, job->job_id);
2526 len = strlenW(filename);
2527 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2528 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2529 job->document_title = strdupW(default_doc_title);
2530 list_add_tail(&printer->queue->jobs, &job->entry);
2532 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2533 if(*pcbNeeded <= cbBuf) {
2534 addjob = (ADDJOB_INFO_1W*)pData;
2535 addjob->JobId = job->job_id;
2536 addjob->Path = (WCHAR *)(addjob + 1);
2537 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2538 ret = TRUE;
2539 } else
2540 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2542 end:
2543 LeaveCriticalSection(&printer_handles_cs);
2544 return ret;
2547 /*****************************************************************************
2548 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2550 * Return the PATH for the Print-Processors
2552 * See GetPrintProcessorDirectoryW.
2556 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2557 DWORD level, LPBYTE Info,
2558 DWORD cbBuf, LPDWORD pcbNeeded)
2560 LPWSTR serverW = NULL;
2561 LPWSTR envW = NULL;
2562 BOOL ret;
2563 INT len;
2565 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2566 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2569 if (server) {
2570 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2571 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2572 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2575 if (env) {
2576 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2577 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2578 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2581 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2582 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2584 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2585 cbBuf, pcbNeeded);
2587 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2588 cbBuf, NULL, NULL) > 0;
2591 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2592 HeapFree(GetProcessHeap(), 0, envW);
2593 HeapFree(GetProcessHeap(), 0, serverW);
2594 return ret;
2597 /*****************************************************************************
2598 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2600 * Return the PATH for the Print-Processors
2602 * PARAMS
2603 * server [I] Servername (NT only) or NULL (local Computer)
2604 * env [I] Printing-Environment (see below) or NULL (Default)
2605 * level [I] Structure-Level (must be 1)
2606 * Info [O] PTR to Buffer that receives the Result
2607 * cbBuf [I] Size of Buffer at "Info"
2608 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2609 * required for the Buffer at "Info"
2611 * RETURNS
2612 * Success: TRUE and in pcbNeeded the Bytes used in Info
2613 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2614 * if cbBuf is too small
2616 * Native Values returned in Info on Success:
2617 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2618 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2619 *| win9x(Windows 4.0): "%winsysdir%"
2621 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2623 * BUGS
2624 * Only NULL or "" is supported for server
2627 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2628 DWORD level, LPBYTE Info,
2629 DWORD cbBuf, LPDWORD pcbNeeded)
2631 DWORD needed;
2632 const printenv_t * env_t;
2634 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2635 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2637 if(server != NULL && server[0]) {
2638 FIXME("server not supported: %s\n", debugstr_w(server));
2639 SetLastError(ERROR_INVALID_PARAMETER);
2640 return FALSE;
2643 env_t = validate_envW(env);
2644 if(!env_t) return FALSE; /* environment invalid or unsupported */
2646 if(level != 1) {
2647 WARN("(Level: %d) is ignored in win9x\n", level);
2648 SetLastError(ERROR_INVALID_LEVEL);
2649 return FALSE;
2652 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2653 needed = GetSystemDirectoryW(NULL, 0);
2654 /* add the Size for the Subdirectories */
2655 needed += lstrlenW(spoolprtprocsW);
2656 needed += lstrlenW(env_t->subdir);
2657 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2659 if(pcbNeeded) *pcbNeeded = needed;
2660 TRACE ("required: 0x%x/%d\n", needed, needed);
2661 if (needed > cbBuf) {
2662 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2663 return FALSE;
2665 if(pcbNeeded == NULL) {
2666 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2667 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2668 SetLastError(RPC_X_NULL_REF_POINTER);
2669 return FALSE;
2671 if(Info == NULL) {
2672 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2673 SetLastError(RPC_X_NULL_REF_POINTER);
2674 return FALSE;
2677 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2678 /* add the Subdirectories */
2679 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2680 lstrcatW((LPWSTR) Info, env_t->subdir);
2681 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2682 return TRUE;
2685 /*****************************************************************************
2686 * WINSPOOL_OpenDriverReg [internal]
2688 * opens the registry for the printer drivers depending on the given input
2689 * variable pEnvironment
2691 * RETURNS:
2692 * the opened hkey on success
2693 * NULL on error
2695 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2697 HKEY retval = NULL;
2698 LPWSTR buffer;
2699 const printenv_t * env;
2701 TRACE("(%s, %d)\n",
2702 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2704 if (!pEnvironment || unicode) {
2705 /* pEnvironment was NULL or an Unicode-String: use it direct */
2706 env = validate_envW(pEnvironment);
2708 else
2710 /* pEnvironment was an ANSI-String: convert to unicode first */
2711 LPWSTR buffer;
2712 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2713 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2714 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2715 env = validate_envW(buffer);
2716 HeapFree(GetProcessHeap(), 0, buffer);
2718 if (!env) return NULL;
2720 buffer = HeapAlloc( GetProcessHeap(), 0,
2721 (strlenW(DriversW) + strlenW(env->envname) +
2722 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2723 if(buffer) {
2724 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2725 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2726 HeapFree(GetProcessHeap(), 0, buffer);
2728 return retval;
2731 /*****************************************************************************
2732 * AddPrinterW [WINSPOOL.@]
2734 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2736 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2737 LPDEVMODEA dmA;
2738 LPDEVMODEW dmW;
2739 HANDLE retval;
2740 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2741 LONG size;
2742 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2743 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2744 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2745 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2746 statusW[] = {'S','t','a','t','u','s',0},
2747 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2749 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2751 if(pName != NULL) {
2752 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2753 SetLastError(ERROR_INVALID_PARAMETER);
2754 return 0;
2756 if(Level != 2) {
2757 ERR("Level = %d, unsupported!\n", Level);
2758 SetLastError(ERROR_INVALID_LEVEL);
2759 return 0;
2761 if(!pPrinter) {
2762 SetLastError(ERROR_INVALID_PARAMETER);
2763 return 0;
2765 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2766 ERROR_SUCCESS) {
2767 ERR("Can't create Printers key\n");
2768 return 0;
2770 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2771 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2772 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2773 RegCloseKey(hkeyPrinter);
2774 RegCloseKey(hkeyPrinters);
2775 return 0;
2777 RegCloseKey(hkeyPrinter);
2779 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2780 if(!hkeyDrivers) {
2781 ERR("Can't create Drivers key\n");
2782 RegCloseKey(hkeyPrinters);
2783 return 0;
2785 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2786 ERROR_SUCCESS) {
2787 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2788 RegCloseKey(hkeyPrinters);
2789 RegCloseKey(hkeyDrivers);
2790 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2791 return 0;
2793 RegCloseKey(hkeyDriver);
2794 RegCloseKey(hkeyDrivers);
2796 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2797 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2798 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2799 RegCloseKey(hkeyPrinters);
2800 return 0;
2803 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2804 ERROR_SUCCESS) {
2805 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2806 SetLastError(ERROR_INVALID_PRINTER_NAME);
2807 RegCloseKey(hkeyPrinters);
2808 return 0;
2810 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2811 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2812 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2814 /* See if we can load the driver. We may need the devmode structure anyway
2816 * FIXME:
2817 * Note that DocumentPropertiesW will briefly try to open the printer we
2818 * just create to find a DEVMODEA struct (it will use the WINEPS default
2819 * one in case it is not there, so we are ok).
2821 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2823 if(size < 0) {
2824 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2825 size = sizeof(DEVMODEW);
2827 if(pi->pDevMode)
2828 dmW = pi->pDevMode;
2829 else
2831 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2832 dmW->dmSize = size;
2833 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2835 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2836 HeapFree(GetProcessHeap(),0,dmW);
2837 dmW=NULL;
2839 else
2841 /* set devmode to printer name */
2842 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2846 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2847 and we support these drivers. NT writes DEVMODEW so somehow
2848 we'll need to distinguish between these when we support NT
2849 drivers */
2850 if (dmW)
2852 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2853 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2854 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2855 HeapFree(GetProcessHeap(), 0, dmA);
2856 if(!pi->pDevMode)
2857 HeapFree(GetProcessHeap(), 0, dmW);
2859 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2860 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2861 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2862 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2864 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2865 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2866 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2867 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2868 (LPBYTE)&pi->Priority, sizeof(DWORD));
2869 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2870 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2871 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2872 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2873 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2874 (LPBYTE)&pi->Status, sizeof(DWORD));
2875 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2876 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2878 RegCloseKey(hkeyPrinter);
2879 RegCloseKey(hkeyPrinters);
2880 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2881 ERR("OpenPrinter failing\n");
2882 return 0;
2884 return retval;
2887 /*****************************************************************************
2888 * AddPrinterA [WINSPOOL.@]
2890 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2892 UNICODE_STRING pNameW;
2893 PWSTR pwstrNameW;
2894 PRINTER_INFO_2W *piW;
2895 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2896 HANDLE ret;
2898 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2899 if(Level != 2) {
2900 ERR("Level = %d, unsupported!\n", Level);
2901 SetLastError(ERROR_INVALID_LEVEL);
2902 return 0;
2904 pwstrNameW = asciitounicode(&pNameW,pName);
2905 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2907 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2909 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2910 RtlFreeUnicodeString(&pNameW);
2911 return ret;
2915 /*****************************************************************************
2916 * ClosePrinter [WINSPOOL.@]
2918 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2920 UINT_PTR i = (UINT_PTR)hPrinter;
2921 opened_printer_t *printer = NULL;
2922 BOOL ret = FALSE;
2924 TRACE("(%p)\n", hPrinter);
2926 EnterCriticalSection(&printer_handles_cs);
2928 if ((i > 0) && (i <= nb_printer_handles))
2929 printer = printer_handles[i - 1];
2932 if(printer)
2934 struct list *cursor, *cursor2;
2936 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer->pm,
2937 debugstr_w(printer->pm ? printer->pm->dllname : NULL),
2938 printer->hXcv, debugstr_w(printer->name), printer->doc );
2940 if(printer->doc)
2941 EndDocPrinter(hPrinter);
2943 if(InterlockedDecrement(&printer->queue->ref) == 0)
2945 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2947 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2948 ScheduleJob(hPrinter, job->job_id);
2950 HeapFree(GetProcessHeap(), 0, printer->queue);
2952 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
2953 monitor_unload(printer->pm);
2954 HeapFree(GetProcessHeap(), 0, printer->printername);
2955 HeapFree(GetProcessHeap(), 0, printer->name);
2956 HeapFree(GetProcessHeap(), 0, printer);
2957 printer_handles[i - 1] = NULL;
2958 ret = TRUE;
2960 LeaveCriticalSection(&printer_handles_cs);
2961 return ret;
2964 /*****************************************************************************
2965 * DeleteFormA [WINSPOOL.@]
2967 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2969 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2970 return 1;
2973 /*****************************************************************************
2974 * DeleteFormW [WINSPOOL.@]
2976 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2978 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2979 return 1;
2982 /*****************************************************************************
2983 * DeletePrinter [WINSPOOL.@]
2985 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2987 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2988 HKEY hkeyPrinters, hkey;
2990 if(!lpNameW) {
2991 SetLastError(ERROR_INVALID_HANDLE);
2992 return FALSE;
2994 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2995 RegDeleteTreeW(hkeyPrinters, lpNameW);
2996 RegCloseKey(hkeyPrinters);
2998 WriteProfileStringW(devicesW, lpNameW, NULL);
2999 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3000 RegDeleteValueW(hkey, lpNameW);
3001 RegCloseKey(hkey);
3003 return TRUE;
3006 /*****************************************************************************
3007 * SetPrinterA [WINSPOOL.@]
3009 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3010 DWORD Command)
3012 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
3013 return FALSE;
3016 /*****************************************************************************
3017 * SetJobA [WINSPOOL.@]
3019 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3020 LPBYTE pJob, DWORD Command)
3022 BOOL ret;
3023 LPBYTE JobW;
3024 UNICODE_STRING usBuffer;
3026 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3028 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3029 are all ignored by SetJob, so we don't bother copying them */
3030 switch(Level)
3032 case 0:
3033 JobW = NULL;
3034 break;
3035 case 1:
3037 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3038 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3040 JobW = (LPBYTE)info1W;
3041 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3042 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3043 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3044 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3045 info1W->Status = info1A->Status;
3046 info1W->Priority = info1A->Priority;
3047 info1W->Position = info1A->Position;
3048 info1W->PagesPrinted = info1A->PagesPrinted;
3049 break;
3051 case 2:
3053 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3054 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3056 JobW = (LPBYTE)info2W;
3057 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3058 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3059 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3060 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3061 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3062 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3063 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3064 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3065 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3066 info2W->Status = info2A->Status;
3067 info2W->Priority = info2A->Priority;
3068 info2W->Position = info2A->Position;
3069 info2W->StartTime = info2A->StartTime;
3070 info2W->UntilTime = info2A->UntilTime;
3071 info2W->PagesPrinted = info2A->PagesPrinted;
3072 break;
3074 case 3:
3075 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3076 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3077 break;
3078 default:
3079 SetLastError(ERROR_INVALID_LEVEL);
3080 return FALSE;
3083 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3085 switch(Level)
3087 case 1:
3089 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3090 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3091 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3092 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3093 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3094 break;
3096 case 2:
3098 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3099 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3100 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3101 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3102 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3103 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3104 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3105 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3106 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3107 break;
3110 HeapFree(GetProcessHeap(), 0, JobW);
3112 return ret;
3115 /*****************************************************************************
3116 * SetJobW [WINSPOOL.@]
3118 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3119 LPBYTE pJob, DWORD Command)
3121 BOOL ret = FALSE;
3122 job_t *job;
3124 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3125 FIXME("Ignoring everything other than document title\n");
3127 EnterCriticalSection(&printer_handles_cs);
3128 job = get_job(hPrinter, JobId);
3129 if(!job)
3130 goto end;
3132 switch(Level)
3134 case 0:
3135 break;
3136 case 1:
3138 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3139 HeapFree(GetProcessHeap(), 0, job->document_title);
3140 job->document_title = strdupW(info1->pDocument);
3141 break;
3143 case 2:
3145 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3146 HeapFree(GetProcessHeap(), 0, job->document_title);
3147 job->document_title = strdupW(info2->pDocument);
3148 break;
3150 case 3:
3151 break;
3152 default:
3153 SetLastError(ERROR_INVALID_LEVEL);
3154 goto end;
3156 ret = TRUE;
3157 end:
3158 LeaveCriticalSection(&printer_handles_cs);
3159 return ret;
3162 /*****************************************************************************
3163 * EndDocPrinter [WINSPOOL.@]
3165 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3167 opened_printer_t *printer;
3168 BOOL ret = FALSE;
3169 TRACE("(%p)\n", hPrinter);
3171 EnterCriticalSection(&printer_handles_cs);
3173 printer = get_opened_printer(hPrinter);
3174 if(!printer)
3176 SetLastError(ERROR_INVALID_HANDLE);
3177 goto end;
3180 if(!printer->doc)
3182 SetLastError(ERROR_SPL_NO_STARTDOC);
3183 goto end;
3186 CloseHandle(printer->doc->hf);
3187 ScheduleJob(hPrinter, printer->doc->job_id);
3188 HeapFree(GetProcessHeap(), 0, printer->doc);
3189 printer->doc = NULL;
3190 ret = TRUE;
3191 end:
3192 LeaveCriticalSection(&printer_handles_cs);
3193 return ret;
3196 /*****************************************************************************
3197 * EndPagePrinter [WINSPOOL.@]
3199 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3201 FIXME("(%p): stub\n", hPrinter);
3202 return TRUE;
3205 /*****************************************************************************
3206 * StartDocPrinterA [WINSPOOL.@]
3208 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3210 UNICODE_STRING usBuffer;
3211 DOC_INFO_2W doc2W;
3212 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3213 DWORD ret;
3215 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3216 or one (DOC_INFO_3) extra DWORDs */
3218 switch(Level) {
3219 case 2:
3220 doc2W.JobId = doc2->JobId;
3221 /* fall through */
3222 case 3:
3223 doc2W.dwMode = doc2->dwMode;
3224 /* fall through */
3225 case 1:
3226 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3227 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3228 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3229 break;
3231 default:
3232 SetLastError(ERROR_INVALID_LEVEL);
3233 return FALSE;
3236 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3238 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3239 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3240 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3242 return ret;
3245 /*****************************************************************************
3246 * StartDocPrinterW [WINSPOOL.@]
3248 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3250 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3251 opened_printer_t *printer;
3252 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3253 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3254 JOB_INFO_1W job_info;
3255 DWORD needed, ret = 0;
3256 HANDLE hf;
3257 WCHAR *filename;
3259 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3260 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3261 debugstr_w(doc->pDatatype));
3263 if(Level < 1 || Level > 3)
3265 SetLastError(ERROR_INVALID_LEVEL);
3266 return 0;
3269 EnterCriticalSection(&printer_handles_cs);
3270 printer = get_opened_printer(hPrinter);
3271 if(!printer)
3273 SetLastError(ERROR_INVALID_HANDLE);
3274 goto end;
3277 if(printer->doc)
3279 SetLastError(ERROR_INVALID_PRINTER_STATE);
3280 goto end;
3283 /* Even if we're printing to a file we still add a print job, we'll
3284 just ignore the spool file name */
3286 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3288 ERR("AddJob failed gle %u\n", GetLastError());
3289 goto end;
3292 if(doc->pOutputFile)
3293 filename = doc->pOutputFile;
3294 else
3295 filename = addjob->Path;
3297 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3298 if(hf == INVALID_HANDLE_VALUE)
3299 goto end;
3301 memset(&job_info, 0, sizeof(job_info));
3302 job_info.pDocument = doc->pDocName;
3303 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3305 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3306 printer->doc->hf = hf;
3307 ret = printer->doc->job_id = addjob->JobId;
3308 end:
3309 LeaveCriticalSection(&printer_handles_cs);
3311 return ret;
3314 /*****************************************************************************
3315 * StartPagePrinter [WINSPOOL.@]
3317 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3319 FIXME("(%p): stub\n", hPrinter);
3320 return TRUE;
3323 /*****************************************************************************
3324 * GetFormA [WINSPOOL.@]
3326 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3327 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3329 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3330 Level,pForm,cbBuf,pcbNeeded);
3331 return FALSE;
3334 /*****************************************************************************
3335 * GetFormW [WINSPOOL.@]
3337 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3338 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3340 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3341 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3342 return FALSE;
3345 /*****************************************************************************
3346 * SetFormA [WINSPOOL.@]
3348 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3349 LPBYTE pForm)
3351 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3352 return FALSE;
3355 /*****************************************************************************
3356 * SetFormW [WINSPOOL.@]
3358 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3359 LPBYTE pForm)
3361 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3362 return FALSE;
3365 /*****************************************************************************
3366 * ReadPrinter [WINSPOOL.@]
3368 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3369 LPDWORD pNoBytesRead)
3371 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3372 return FALSE;
3375 /*****************************************************************************
3376 * ResetPrinterA [WINSPOOL.@]
3378 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3380 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3381 return FALSE;
3384 /*****************************************************************************
3385 * ResetPrinterW [WINSPOOL.@]
3387 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3389 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3390 return FALSE;
3393 /*****************************************************************************
3394 * WINSPOOL_GetDWORDFromReg
3396 * Return DWORD associated with ValueName from hkey.
3398 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3400 DWORD sz = sizeof(DWORD), type, value = 0;
3401 LONG ret;
3403 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3405 if(ret != ERROR_SUCCESS) {
3406 WARN("Got ret = %d on name %s\n", ret, ValueName);
3407 return 0;
3409 if(type != REG_DWORD) {
3410 ERR("Got type %d\n", type);
3411 return 0;
3413 return value;
3416 /*****************************************************************************
3417 * WINSPOOL_GetStringFromReg
3419 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3420 * String is stored either as unicode or ascii.
3421 * Bit of a hack here to get the ValueName if we want ascii.
3423 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3424 DWORD buflen, DWORD *needed,
3425 BOOL unicode)
3427 DWORD sz = buflen, type;
3428 LONG ret;
3430 if(unicode)
3431 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3432 else {
3433 LPSTR ValueNameA = strdupWtoA(ValueName);
3434 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3435 HeapFree(GetProcessHeap(),0,ValueNameA);
3437 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3438 WARN("Got ret = %d\n", ret);
3439 *needed = 0;
3440 return FALSE;
3442 /* add space for terminating '\0' */
3443 sz += unicode ? sizeof(WCHAR) : 1;
3444 *needed = sz;
3446 if (ptr)
3447 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3449 return TRUE;
3452 /*****************************************************************************
3453 * WINSPOOL_GetDefaultDevMode
3455 * Get a default DevMode values for wineps.
3456 * FIXME - use ppd.
3459 static void WINSPOOL_GetDefaultDevMode(
3460 LPBYTE ptr,
3461 DWORD buflen, DWORD *needed,
3462 BOOL unicode)
3464 DEVMODEA dm;
3465 static const char szwps[] = "wineps.drv";
3467 /* fill default DEVMODE - should be read from ppd... */
3468 ZeroMemory( &dm, sizeof(dm) );
3469 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3470 dm.dmSpecVersion = DM_SPECVERSION;
3471 dm.dmDriverVersion = 1;
3472 dm.dmSize = sizeof(DEVMODEA);
3473 dm.dmDriverExtra = 0;
3474 dm.dmFields =
3475 DM_ORIENTATION | DM_PAPERSIZE |
3476 DM_PAPERLENGTH | DM_PAPERWIDTH |
3477 DM_SCALE |
3478 DM_COPIES |
3479 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3480 DM_YRESOLUTION | DM_TTOPTION;
3482 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3483 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3484 dm.u1.s1.dmPaperLength = 2970;
3485 dm.u1.s1.dmPaperWidth = 2100;
3487 dm.dmScale = 100;
3488 dm.dmCopies = 1;
3489 dm.dmDefaultSource = DMBIN_AUTO;
3490 dm.dmPrintQuality = DMRES_MEDIUM;
3491 /* dm.dmColor */
3492 /* dm.dmDuplex */
3493 dm.dmYResolution = 300; /* 300dpi */
3494 dm.dmTTOption = DMTT_BITMAP;
3495 /* dm.dmCollate */
3496 /* dm.dmFormName */
3497 /* dm.dmLogPixels */
3498 /* dm.dmBitsPerPel */
3499 /* dm.dmPelsWidth */
3500 /* dm.dmPelsHeight */
3501 /* dm.dmDisplayFlags */
3502 /* dm.dmDisplayFrequency */
3503 /* dm.dmICMMethod */
3504 /* dm.dmICMIntent */
3505 /* dm.dmMediaType */
3506 /* dm.dmDitherType */
3507 /* dm.dmReserved1 */
3508 /* dm.dmReserved2 */
3509 /* dm.dmPanningWidth */
3510 /* dm.dmPanningHeight */
3512 if(unicode) {
3513 if(buflen >= sizeof(DEVMODEW)) {
3514 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3515 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3516 HeapFree(GetProcessHeap(),0,pdmW);
3518 *needed = sizeof(DEVMODEW);
3520 else
3522 if(buflen >= sizeof(DEVMODEA)) {
3523 memcpy(ptr, &dm, sizeof(DEVMODEA));
3525 *needed = sizeof(DEVMODEA);
3529 /*****************************************************************************
3530 * WINSPOOL_GetDevModeFromReg
3532 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3533 * DevMode is stored either as unicode or ascii.
3535 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3536 LPBYTE ptr,
3537 DWORD buflen, DWORD *needed,
3538 BOOL unicode)
3540 DWORD sz = buflen, type;
3541 LONG ret;
3543 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3544 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3545 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3546 if (sz < sizeof(DEVMODEA))
3548 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3549 return FALSE;
3551 /* ensures that dmSize is not erratically bogus if registry is invalid */
3552 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3553 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3554 if(unicode) {
3555 sz += (CCHDEVICENAME + CCHFORMNAME);
3556 if(buflen >= sz) {
3557 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3558 memcpy(ptr, dmW, sz);
3559 HeapFree(GetProcessHeap(),0,dmW);
3562 *needed = sz;
3563 return TRUE;
3566 /*********************************************************************
3567 * WINSPOOL_GetPrinter_1
3569 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3570 * The strings are either stored as unicode or ascii.
3572 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3573 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3574 BOOL unicode)
3576 DWORD size, left = cbBuf;
3577 BOOL space = (cbBuf > 0);
3578 LPBYTE ptr = buf;
3580 *pcbNeeded = 0;
3582 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3583 unicode)) {
3584 if(space && size <= left) {
3585 pi1->pName = (LPWSTR)ptr;
3586 ptr += size;
3587 left -= size;
3588 } else
3589 space = FALSE;
3590 *pcbNeeded += size;
3593 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3594 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3595 unicode)) {
3596 if(space && size <= left) {
3597 pi1->pDescription = (LPWSTR)ptr;
3598 ptr += size;
3599 left -= size;
3600 } else
3601 space = FALSE;
3602 *pcbNeeded += size;
3605 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3606 unicode)) {
3607 if(space && size <= left) {
3608 pi1->pComment = (LPWSTR)ptr;
3609 ptr += size;
3610 left -= size;
3611 } else
3612 space = FALSE;
3613 *pcbNeeded += size;
3616 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3618 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3619 memset(pi1, 0, sizeof(*pi1));
3621 return space;
3623 /*********************************************************************
3624 * WINSPOOL_GetPrinter_2
3626 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3627 * The strings are either stored as unicode or ascii.
3629 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3630 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3631 BOOL unicode)
3633 DWORD size, left = cbBuf;
3634 BOOL space = (cbBuf > 0);
3635 LPBYTE ptr = buf;
3637 *pcbNeeded = 0;
3639 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3640 unicode)) {
3641 if(space && size <= left) {
3642 pi2->pPrinterName = (LPWSTR)ptr;
3643 ptr += size;
3644 left -= size;
3645 } else
3646 space = FALSE;
3647 *pcbNeeded += size;
3649 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3650 unicode)) {
3651 if(space && size <= left) {
3652 pi2->pShareName = (LPWSTR)ptr;
3653 ptr += size;
3654 left -= size;
3655 } else
3656 space = FALSE;
3657 *pcbNeeded += size;
3659 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3660 unicode)) {
3661 if(space && size <= left) {
3662 pi2->pPortName = (LPWSTR)ptr;
3663 ptr += size;
3664 left -= size;
3665 } else
3666 space = FALSE;
3667 *pcbNeeded += size;
3669 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3670 &size, unicode)) {
3671 if(space && size <= left) {
3672 pi2->pDriverName = (LPWSTR)ptr;
3673 ptr += size;
3674 left -= size;
3675 } else
3676 space = FALSE;
3677 *pcbNeeded += size;
3679 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3680 unicode)) {
3681 if(space && size <= left) {
3682 pi2->pComment = (LPWSTR)ptr;
3683 ptr += size;
3684 left -= size;
3685 } else
3686 space = FALSE;
3687 *pcbNeeded += size;
3689 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3690 unicode)) {
3691 if(space && size <= left) {
3692 pi2->pLocation = (LPWSTR)ptr;
3693 ptr += size;
3694 left -= size;
3695 } else
3696 space = FALSE;
3697 *pcbNeeded += size;
3699 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3700 &size, unicode)) {
3701 if(space && size <= left) {
3702 pi2->pDevMode = (LPDEVMODEW)ptr;
3703 ptr += size;
3704 left -= size;
3705 } else
3706 space = FALSE;
3707 *pcbNeeded += size;
3709 else
3711 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3712 if(space && size <= left) {
3713 pi2->pDevMode = (LPDEVMODEW)ptr;
3714 ptr += size;
3715 left -= size;
3716 } else
3717 space = FALSE;
3718 *pcbNeeded += size;
3720 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3721 &size, unicode)) {
3722 if(space && size <= left) {
3723 pi2->pSepFile = (LPWSTR)ptr;
3724 ptr += size;
3725 left -= size;
3726 } else
3727 space = FALSE;
3728 *pcbNeeded += size;
3730 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3731 &size, unicode)) {
3732 if(space && size <= left) {
3733 pi2->pPrintProcessor = (LPWSTR)ptr;
3734 ptr += size;
3735 left -= size;
3736 } else
3737 space = FALSE;
3738 *pcbNeeded += size;
3740 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3741 &size, unicode)) {
3742 if(space && size <= left) {
3743 pi2->pDatatype = (LPWSTR)ptr;
3744 ptr += size;
3745 left -= size;
3746 } else
3747 space = FALSE;
3748 *pcbNeeded += size;
3750 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3751 &size, unicode)) {
3752 if(space && size <= left) {
3753 pi2->pParameters = (LPWSTR)ptr;
3754 ptr += size;
3755 left -= size;
3756 } else
3757 space = FALSE;
3758 *pcbNeeded += size;
3760 if(pi2) {
3761 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3762 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3763 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3764 "Default Priority");
3765 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3766 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3769 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3770 memset(pi2, 0, sizeof(*pi2));
3772 return space;
3775 /*********************************************************************
3776 * WINSPOOL_GetPrinter_4
3778 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3780 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3781 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3782 BOOL unicode)
3784 DWORD size, left = cbBuf;
3785 BOOL space = (cbBuf > 0);
3786 LPBYTE ptr = buf;
3788 *pcbNeeded = 0;
3790 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3791 unicode)) {
3792 if(space && size <= left) {
3793 pi4->pPrinterName = (LPWSTR)ptr;
3794 ptr += size;
3795 left -= size;
3796 } else
3797 space = FALSE;
3798 *pcbNeeded += size;
3800 if(pi4) {
3801 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3804 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3805 memset(pi4, 0, sizeof(*pi4));
3807 return space;
3810 /*********************************************************************
3811 * WINSPOOL_GetPrinter_5
3813 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3815 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3816 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3817 BOOL unicode)
3819 DWORD size, left = cbBuf;
3820 BOOL space = (cbBuf > 0);
3821 LPBYTE ptr = buf;
3823 *pcbNeeded = 0;
3825 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3826 unicode)) {
3827 if(space && size <= left) {
3828 pi5->pPrinterName = (LPWSTR)ptr;
3829 ptr += size;
3830 left -= size;
3831 } else
3832 space = FALSE;
3833 *pcbNeeded += size;
3835 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3836 unicode)) {
3837 if(space && size <= left) {
3838 pi5->pPortName = (LPWSTR)ptr;
3839 ptr += size;
3840 left -= size;
3841 } else
3842 space = FALSE;
3843 *pcbNeeded += size;
3845 if(pi5) {
3846 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3847 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3848 "dnsTimeout");
3849 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3850 "txTimeout");
3853 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3854 memset(pi5, 0, sizeof(*pi5));
3856 return space;
3859 /*****************************************************************************
3860 * WINSPOOL_GetPrinter
3862 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3863 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3864 * just a collection of pointers to strings.
3866 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3867 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3869 LPCWSTR name;
3870 DWORD size, needed = 0;
3871 LPBYTE ptr = NULL;
3872 HKEY hkeyPrinter, hkeyPrinters;
3873 BOOL ret;
3875 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3877 if (!(name = get_opened_printer_name(hPrinter))) {
3878 SetLastError(ERROR_INVALID_HANDLE);
3879 return FALSE;
3882 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3883 ERROR_SUCCESS) {
3884 ERR("Can't create Printers key\n");
3885 return FALSE;
3887 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3889 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3890 RegCloseKey(hkeyPrinters);
3891 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3892 return FALSE;
3895 switch(Level) {
3896 case 2:
3898 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3900 size = sizeof(PRINTER_INFO_2W);
3901 if(size <= cbBuf) {
3902 ptr = pPrinter + size;
3903 cbBuf -= size;
3904 memset(pPrinter, 0, size);
3905 } else {
3906 pi2 = NULL;
3907 cbBuf = 0;
3909 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3910 unicode);
3911 needed += size;
3912 break;
3915 case 4:
3917 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3919 size = sizeof(PRINTER_INFO_4W);
3920 if(size <= cbBuf) {
3921 ptr = pPrinter + size;
3922 cbBuf -= size;
3923 memset(pPrinter, 0, size);
3924 } else {
3925 pi4 = NULL;
3926 cbBuf = 0;
3928 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
3929 unicode);
3930 needed += size;
3931 break;
3935 case 5:
3937 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3939 size = sizeof(PRINTER_INFO_5W);
3940 if(size <= cbBuf) {
3941 ptr = pPrinter + size;
3942 cbBuf -= size;
3943 memset(pPrinter, 0, size);
3944 } else {
3945 pi5 = NULL;
3946 cbBuf = 0;
3949 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
3950 unicode);
3951 needed += size;
3952 break;
3955 default:
3956 FIXME("Unimplemented level %d\n", Level);
3957 SetLastError(ERROR_INVALID_LEVEL);
3958 RegCloseKey(hkeyPrinters);
3959 RegCloseKey(hkeyPrinter);
3960 return FALSE;
3963 RegCloseKey(hkeyPrinter);
3964 RegCloseKey(hkeyPrinters);
3966 TRACE("returning %d needed = %d\n", ret, needed);
3967 if(pcbNeeded) *pcbNeeded = needed;
3968 if(!ret)
3969 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3970 return ret;
3973 /*****************************************************************************
3974 * GetPrinterW [WINSPOOL.@]
3976 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3977 DWORD cbBuf, LPDWORD pcbNeeded)
3979 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3980 TRUE);
3983 /*****************************************************************************
3984 * GetPrinterA [WINSPOOL.@]
3986 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3987 DWORD cbBuf, LPDWORD pcbNeeded)
3989 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3990 FALSE);
3993 /*****************************************************************************
3994 * WINSPOOL_EnumPrinters
3996 * Implementation of EnumPrintersA|W
3998 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
3999 DWORD dwLevel, LPBYTE lpbPrinters,
4000 DWORD cbBuf, LPDWORD lpdwNeeded,
4001 LPDWORD lpdwReturned, BOOL unicode)
4004 HKEY hkeyPrinters, hkeyPrinter;
4005 WCHAR PrinterName[255];
4006 DWORD needed = 0, number = 0;
4007 DWORD used, i, left;
4008 PBYTE pi, buf;
4010 if(lpbPrinters)
4011 memset(lpbPrinters, 0, cbBuf);
4012 if(lpdwReturned)
4013 *lpdwReturned = 0;
4014 if(lpdwNeeded)
4015 *lpdwNeeded = 0;
4017 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4018 if(dwType == PRINTER_ENUM_DEFAULT)
4019 return TRUE;
4021 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4022 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4023 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4024 if (!dwType) {
4025 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4026 *lpdwNeeded = 0;
4027 *lpdwReturned = 0;
4028 return TRUE;
4033 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4034 FIXME("dwType = %08x\n", dwType);
4035 SetLastError(ERROR_INVALID_FLAGS);
4036 return FALSE;
4039 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4040 ERROR_SUCCESS) {
4041 ERR("Can't create Printers key\n");
4042 return FALSE;
4045 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4046 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4047 RegCloseKey(hkeyPrinters);
4048 ERR("Can't query Printers key\n");
4049 return FALSE;
4051 TRACE("Found %d printers\n", number);
4053 switch(dwLevel) {
4054 case 1:
4055 used = number * sizeof(PRINTER_INFO_1W);
4056 break;
4057 case 2:
4058 used = number * sizeof(PRINTER_INFO_2W);
4059 break;
4060 case 4:
4061 used = number * sizeof(PRINTER_INFO_4W);
4062 break;
4063 case 5:
4064 used = number * sizeof(PRINTER_INFO_5W);
4065 break;
4067 default:
4068 SetLastError(ERROR_INVALID_LEVEL);
4069 RegCloseKey(hkeyPrinters);
4070 return FALSE;
4072 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4074 for(i = 0; i < number; i++) {
4075 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
4076 ERROR_SUCCESS) {
4077 ERR("Can't enum key number %d\n", i);
4078 RegCloseKey(hkeyPrinters);
4079 return FALSE;
4081 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4082 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4083 ERROR_SUCCESS) {
4084 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4085 RegCloseKey(hkeyPrinters);
4086 return FALSE;
4089 if(cbBuf > used) {
4090 buf = lpbPrinters + used;
4091 left = cbBuf - used;
4092 } else {
4093 buf = NULL;
4094 left = 0;
4097 switch(dwLevel) {
4098 case 1:
4099 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4100 left, &needed, unicode);
4101 used += needed;
4102 if(pi) pi += sizeof(PRINTER_INFO_1W);
4103 break;
4104 case 2:
4105 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4106 left, &needed, unicode);
4107 used += needed;
4108 if(pi) pi += sizeof(PRINTER_INFO_2W);
4109 break;
4110 case 4:
4111 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4112 left, &needed, unicode);
4113 used += needed;
4114 if(pi) pi += sizeof(PRINTER_INFO_4W);
4115 break;
4116 case 5:
4117 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4118 left, &needed, unicode);
4119 used += needed;
4120 if(pi) pi += sizeof(PRINTER_INFO_5W);
4121 break;
4122 default:
4123 ERR("Shouldn't be here!\n");
4124 RegCloseKey(hkeyPrinter);
4125 RegCloseKey(hkeyPrinters);
4126 return FALSE;
4128 RegCloseKey(hkeyPrinter);
4130 RegCloseKey(hkeyPrinters);
4132 if(lpdwNeeded)
4133 *lpdwNeeded = used;
4135 if(used > cbBuf) {
4136 if(lpbPrinters)
4137 memset(lpbPrinters, 0, cbBuf);
4138 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4139 return FALSE;
4141 if(lpdwReturned)
4142 *lpdwReturned = number;
4143 SetLastError(ERROR_SUCCESS);
4144 return TRUE;
4148 /******************************************************************
4149 * EnumPrintersW [WINSPOOL.@]
4151 * Enumerates the available printers, print servers and print
4152 * providers, depending on the specified flags, name and level.
4154 * RETURNS:
4156 * If level is set to 1:
4157 * Returns an array of PRINTER_INFO_1 data structures in the
4158 * lpbPrinters buffer.
4160 * If level is set to 2:
4161 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4162 * Returns an array of PRINTER_INFO_2 data structures in the
4163 * lpbPrinters buffer. Note that according to MSDN also an
4164 * OpenPrinter should be performed on every remote printer.
4166 * If level is set to 4 (officially WinNT only):
4167 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4168 * Fast: Only the registry is queried to retrieve printer names,
4169 * no connection to the driver is made.
4170 * Returns an array of PRINTER_INFO_4 data structures in the
4171 * lpbPrinters buffer.
4173 * If level is set to 5 (officially WinNT4/Win9x only):
4174 * Fast: Only the registry is queried to retrieve printer names,
4175 * no connection to the driver is made.
4176 * Returns an array of PRINTER_INFO_5 data structures in the
4177 * lpbPrinters buffer.
4179 * If level set to 3 or 6+:
4180 * returns zero (failure!)
4182 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4183 * for information.
4185 * BUGS:
4186 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4187 * - Only levels 2, 4 and 5 are implemented at the moment.
4188 * - 16-bit printer drivers are not enumerated.
4189 * - Returned amount of bytes used/needed does not match the real Windoze
4190 * implementation (as in this implementation, all strings are part
4191 * of the buffer, whereas Win32 keeps them somewhere else)
4192 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4194 * NOTE:
4195 * - In a regular Wine installation, no registry settings for printers
4196 * exist, which makes this function return an empty list.
4198 BOOL WINAPI EnumPrintersW(
4199 DWORD dwType, /* [in] Types of print objects to enumerate */
4200 LPWSTR lpszName, /* [in] name of objects to enumerate */
4201 DWORD dwLevel, /* [in] type of printer info structure */
4202 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4203 DWORD cbBuf, /* [in] max size of buffer in bytes */
4204 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4205 LPDWORD lpdwReturned /* [out] number of entries returned */
4208 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4209 lpdwNeeded, lpdwReturned, TRUE);
4212 /******************************************************************
4213 * EnumPrintersA [WINSPOOL.@]
4216 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
4217 DWORD dwLevel, LPBYTE lpbPrinters,
4218 DWORD cbBuf, LPDWORD lpdwNeeded,
4219 LPDWORD lpdwReturned)
4221 BOOL ret, unicode = FALSE;
4222 UNICODE_STRING lpszNameW;
4223 PWSTR pwstrNameW;
4225 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
4226 if(!cbBuf) unicode = TRUE; /* return a buffer that's big enough for the unicode version */
4227 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
4228 lpdwNeeded, lpdwReturned, unicode);
4229 RtlFreeUnicodeString(&lpszNameW);
4230 return ret;
4233 /*****************************************************************************
4234 * WINSPOOL_GetDriverInfoFromReg [internal]
4236 * Enters the information from the registry into the DRIVER_INFO struct
4238 * RETURNS
4239 * zero if the printer driver does not exist in the registry
4240 * (only if Level > 1) otherwise nonzero
4242 static BOOL WINSPOOL_GetDriverInfoFromReg(
4243 HKEY hkeyDrivers,
4244 LPWSTR DriverName,
4245 const printenv_t * env,
4246 DWORD Level,
4247 LPBYTE ptr, /* DRIVER_INFO */
4248 LPBYTE pDriverStrings, /* strings buffer */
4249 DWORD cbBuf, /* size of string buffer */
4250 LPDWORD pcbNeeded, /* space needed for str. */
4251 BOOL unicode) /* type of strings */
4253 DWORD size, tmp;
4254 HKEY hkeyDriver;
4255 LPBYTE strPtr = pDriverStrings;
4256 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4258 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers,
4259 debugstr_w(DriverName), env,
4260 Level, di, pDriverStrings, cbBuf, unicode);
4262 if (unicode) {
4263 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4264 if (*pcbNeeded <= cbBuf)
4265 strcpyW((LPWSTR)strPtr, DriverName);
4267 else
4269 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL, NULL);
4270 if (*pcbNeeded <= cbBuf)
4271 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4274 /* pName for level 1 has a different offset! */
4275 if (Level == 1) {
4276 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4277 return TRUE;
4280 /* .cVersion and .pName for level > 1 */
4281 if (di) {
4282 di->cVersion = env->driverversion;
4283 di->pName = (LPWSTR) strPtr;
4284 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4287 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4288 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4289 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4290 return FALSE;
4293 /* pEnvironment */
4294 if (unicode)
4295 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4296 else
4297 size = WideCharToMultiByte(CP_ACP, 0, env->envname, -1, NULL, 0, NULL, NULL);
4299 *pcbNeeded += size;
4300 if (*pcbNeeded <= cbBuf) {
4301 if (unicode) {
4302 lstrcpyW((LPWSTR)strPtr, env->envname);
4304 else
4306 WideCharToMultiByte(CP_ACP, 0, env->envname, -1, (LPSTR)strPtr, size, NULL, NULL);
4308 if (di) di->pEnvironment = (LPWSTR)strPtr;
4309 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4313 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
4314 unicode)) {
4315 *pcbNeeded += size;
4316 if(*pcbNeeded <= cbBuf)
4317 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
4318 unicode);
4319 if(ptr)
4320 ((PDRIVER_INFO_2W) ptr)->pDriverPath = (LPWSTR)strPtr;
4321 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4324 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
4325 unicode)) {
4326 *pcbNeeded += size;
4327 if(*pcbNeeded <= cbBuf)
4328 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
4329 &tmp, unicode);
4330 if(ptr)
4331 ((PDRIVER_INFO_2W) ptr)->pDataFile = (LPWSTR)strPtr;
4332 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4335 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
4336 0, &size, unicode)) {
4337 *pcbNeeded += size;
4338 if(*pcbNeeded <= cbBuf)
4339 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
4340 size, &tmp, unicode);
4341 if(ptr)
4342 ((PDRIVER_INFO_2W) ptr)->pConfigFile = (LPWSTR)strPtr;
4343 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4346 if(Level == 2 ) {
4347 RegCloseKey(hkeyDriver);
4348 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4349 return TRUE;
4352 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
4353 unicode)) {
4354 *pcbNeeded += size;
4355 if(*pcbNeeded <= cbBuf)
4356 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
4357 size, &tmp, unicode);
4358 if(ptr)
4359 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
4360 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4363 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
4364 &size, unicode)) {
4365 *pcbNeeded += size;
4366 if(*pcbNeeded <= cbBuf)
4367 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
4368 size, &tmp, unicode);
4369 if(ptr)
4370 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
4371 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4374 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
4375 unicode)) {
4376 *pcbNeeded += size;
4377 if(*pcbNeeded <= cbBuf)
4378 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
4379 size, &tmp, unicode);
4380 if(ptr)
4381 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
4382 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4385 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
4386 unicode)) {
4387 *pcbNeeded += size;
4388 if(*pcbNeeded <= cbBuf)
4389 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
4390 size, &tmp, unicode);
4391 if(ptr)
4392 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
4393 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4396 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4397 RegCloseKey(hkeyDriver);
4398 return TRUE;
4401 /*****************************************************************************
4402 * WINSPOOL_GetPrinterDriver
4404 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
4405 DWORD Level, LPBYTE pDriverInfo,
4406 DWORD cbBuf, LPDWORD pcbNeeded,
4407 BOOL unicode)
4409 LPCWSTR name;
4410 WCHAR DriverName[100];
4411 DWORD ret, type, size, needed = 0;
4412 LPBYTE ptr = NULL;
4413 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4414 const printenv_t * env;
4416 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4417 Level,pDriverInfo,cbBuf, pcbNeeded);
4419 ZeroMemory(pDriverInfo, cbBuf);
4421 if (!(name = get_opened_printer_name(hPrinter))) {
4422 SetLastError(ERROR_INVALID_HANDLE);
4423 return FALSE;
4426 if(Level < 1 || Level > 6) {
4427 SetLastError(ERROR_INVALID_LEVEL);
4428 return FALSE;
4431 env = validate_envW(pEnvironment);
4432 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4434 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4435 ERROR_SUCCESS) {
4436 ERR("Can't create Printers key\n");
4437 return FALSE;
4439 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4440 != ERROR_SUCCESS) {
4441 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4442 RegCloseKey(hkeyPrinters);
4443 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4444 return FALSE;
4446 size = sizeof(DriverName);
4447 DriverName[0] = 0;
4448 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4449 (LPBYTE)DriverName, &size);
4450 RegCloseKey(hkeyPrinter);
4451 RegCloseKey(hkeyPrinters);
4452 if(ret != ERROR_SUCCESS) {
4453 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4454 return FALSE;
4457 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4458 if(!hkeyDrivers) {
4459 ERR("Can't create Drivers key\n");
4460 return FALSE;
4463 switch(Level) {
4464 case 1:
4465 size = sizeof(DRIVER_INFO_1W);
4466 break;
4467 case 2:
4468 size = sizeof(DRIVER_INFO_2W);
4469 break;
4470 case 3:
4471 size = sizeof(DRIVER_INFO_3W);
4472 break;
4473 case 4:
4474 size = sizeof(DRIVER_INFO_4W);
4475 break;
4476 case 5:
4477 size = sizeof(DRIVER_INFO_5W);
4478 break;
4479 case 6:
4480 size = sizeof(DRIVER_INFO_6W);
4481 break;
4482 default:
4483 ERR("Invalid level\n");
4484 return FALSE;
4487 if(size <= cbBuf)
4488 ptr = pDriverInfo + size;
4490 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4491 env, Level, pDriverInfo,
4492 (cbBuf < size) ? NULL : ptr,
4493 (cbBuf < size) ? 0 : cbBuf - size,
4494 &needed, unicode)) {
4495 RegCloseKey(hkeyDrivers);
4496 return FALSE;
4499 RegCloseKey(hkeyDrivers);
4501 if(pcbNeeded) *pcbNeeded = size + needed;
4502 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4503 if(cbBuf >= needed) return TRUE;
4504 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4505 return FALSE;
4508 /*****************************************************************************
4509 * GetPrinterDriverA [WINSPOOL.@]
4511 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4512 DWORD Level, LPBYTE pDriverInfo,
4513 DWORD cbBuf, LPDWORD pcbNeeded)
4515 BOOL ret;
4516 UNICODE_STRING pEnvW;
4517 PWSTR pwstrEnvW;
4519 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4520 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4521 cbBuf, pcbNeeded, FALSE);
4522 RtlFreeUnicodeString(&pEnvW);
4523 return ret;
4525 /*****************************************************************************
4526 * GetPrinterDriverW [WINSPOOL.@]
4528 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4529 DWORD Level, LPBYTE pDriverInfo,
4530 DWORD cbBuf, LPDWORD pcbNeeded)
4532 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4533 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4536 /*****************************************************************************
4537 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4539 * Return the PATH for the Printer-Drivers (UNICODE)
4541 * PARAMS
4542 * pName [I] Servername (NT only) or NULL (local Computer)
4543 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4544 * Level [I] Structure-Level (must be 1)
4545 * pDriverDirectory [O] PTR to Buffer that receives the Result
4546 * cbBuf [I] Size of Buffer at pDriverDirectory
4547 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4548 * required for pDriverDirectory
4550 * RETURNS
4551 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4552 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4553 * if cbBuf is too small
4555 * Native Values returned in pDriverDirectory on Success:
4556 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4557 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4558 *| win9x(Windows 4.0): "%winsysdir%"
4560 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4562 * FIXME
4563 *- Only NULL or "" is supported for pName
4566 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4567 DWORD Level, LPBYTE pDriverDirectory,
4568 DWORD cbBuf, LPDWORD pcbNeeded)
4570 DWORD needed;
4571 const printenv_t * env;
4573 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4574 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4575 if(pName != NULL && pName[0]) {
4576 FIXME("pName unsupported: %s\n", debugstr_w(pName));
4577 SetLastError(ERROR_INVALID_PARAMETER);
4578 return FALSE;
4581 env = validate_envW(pEnvironment);
4582 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
4584 if(Level != 1) {
4585 WARN("(Level: %d) is ignored in win9x\n", Level);
4586 SetLastError(ERROR_INVALID_LEVEL);
4587 return FALSE;
4590 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
4591 needed = GetSystemDirectoryW(NULL, 0);
4592 /* add the Size for the Subdirectories */
4593 needed += lstrlenW(spooldriversW);
4594 needed += lstrlenW(env->subdir);
4595 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
4597 if(pcbNeeded)
4598 *pcbNeeded = needed;
4599 TRACE("required: 0x%x/%d\n", needed, needed);
4600 if(needed > cbBuf) {
4601 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4602 return FALSE;
4604 if(pcbNeeded == NULL) {
4605 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
4606 SetLastError(RPC_X_NULL_REF_POINTER);
4607 return FALSE;
4609 if(pDriverDirectory == NULL) {
4610 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
4611 SetLastError(ERROR_INVALID_USER_BUFFER);
4612 return FALSE;
4615 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
4616 /* add the Subdirectories */
4617 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
4618 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
4619 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
4620 return TRUE;
4624 /*****************************************************************************
4625 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4627 * Return the PATH for the Printer-Drivers (ANSI)
4629 * See GetPrinterDriverDirectoryW.
4631 * NOTES
4632 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4635 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4636 DWORD Level, LPBYTE pDriverDirectory,
4637 DWORD cbBuf, LPDWORD pcbNeeded)
4639 UNICODE_STRING nameW, environmentW;
4640 BOOL ret;
4641 DWORD pcbNeededW;
4642 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4643 WCHAR *driverDirectoryW = NULL;
4645 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4646 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4648 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4650 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4651 else nameW.Buffer = NULL;
4652 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4653 else environmentW.Buffer = NULL;
4655 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4656 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4657 if (ret) {
4658 DWORD needed;
4659 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4660 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4661 if(pcbNeeded)
4662 *pcbNeeded = needed;
4663 ret = (needed <= cbBuf) ? TRUE : FALSE;
4664 } else
4665 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4667 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4669 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4670 RtlFreeUnicodeString(&environmentW);
4671 RtlFreeUnicodeString(&nameW);
4673 return ret;
4676 /*****************************************************************************
4677 * AddPrinterDriverA [WINSPOOL.@]
4679 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4681 DRIVER_INFO_3A di3;
4682 HKEY hkeyDrivers, hkeyName;
4683 static CHAR empty[] = "",
4684 nullnull[] = "\0";
4686 TRACE("(%s,%d,%p)\n",debugstr_a(pName),level,pDriverInfo);
4688 if(level != 2 && level != 3) {
4689 SetLastError(ERROR_INVALID_LEVEL);
4690 return FALSE;
4692 if ((pName) && (pName[0])) {
4693 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
4694 SetLastError(ERROR_INVALID_PARAMETER);
4695 return FALSE;
4697 if(!pDriverInfo) {
4698 WARN("pDriverInfo == NULL\n");
4699 SetLastError(ERROR_INVALID_PARAMETER);
4700 return FALSE;
4703 if(level == 3)
4704 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
4705 else {
4706 memset(&di3, 0, sizeof(di3));
4707 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
4710 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
4711 !di3.pDataFile) {
4712 SetLastError(ERROR_INVALID_PARAMETER);
4713 return FALSE;
4716 if(!di3.pDefaultDataType) di3.pDefaultDataType = empty;
4717 if(!di3.pDependentFiles) di3.pDependentFiles = nullnull;
4718 if(!di3.pHelpFile) di3.pHelpFile = empty;
4719 if(!di3.pMonitorName) di3.pMonitorName = empty;
4721 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
4723 if(!hkeyDrivers) {
4724 ERR("Can't create Drivers key\n");
4725 return FALSE;
4728 if(level == 2) { /* apparently can't overwrite with level2 */
4729 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
4730 RegCloseKey(hkeyName);
4731 RegCloseKey(hkeyDrivers);
4732 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
4733 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
4734 return FALSE;
4737 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
4738 RegCloseKey(hkeyDrivers);
4739 ERR("Can't create Name key\n");
4740 return FALSE;
4742 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
4743 lstrlenA(di3.pConfigFile) + 1);
4744 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, lstrlenA(di3.pDataFile) + 1);
4745 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, lstrlenA(di3.pDriverPath) + 1);
4746 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
4747 sizeof(DWORD));
4748 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, lstrlenA(di3.pDefaultDataType));
4749 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
4750 (LPBYTE) di3.pDependentFiles, multi_sz_lenA(di3.pDependentFiles));
4751 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, lstrlenA(di3.pHelpFile) + 1);
4752 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, lstrlenA(di3.pMonitorName) + 1);
4753 RegCloseKey(hkeyName);
4754 RegCloseKey(hkeyDrivers);
4756 return TRUE;
4759 /*****************************************************************************
4760 * AddPrinterDriverW [WINSPOOL.@]
4762 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
4763 LPBYTE pDriverInfo)
4765 FIXME("(%s,%d,%p): stub\n",debugstr_w(printerName),
4766 level,pDriverInfo);
4767 return FALSE;
4770 /*****************************************************************************
4771 * AddPrintProcessorA [WINSPOOL.@]
4773 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4774 LPSTR pPrintProcessorName)
4776 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4777 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4778 return FALSE;
4781 /*****************************************************************************
4782 * AddPrintProcessorW [WINSPOOL.@]
4784 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4785 LPWSTR pPrintProcessorName)
4787 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4788 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4789 return FALSE;
4792 /*****************************************************************************
4793 * AddPrintProvidorA [WINSPOOL.@]
4795 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4797 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4798 return FALSE;
4801 /*****************************************************************************
4802 * AddPrintProvidorW [WINSPOOL.@]
4804 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4806 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4807 return FALSE;
4810 /*****************************************************************************
4811 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4813 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4814 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4816 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4817 pDevModeOutput, pDevModeInput);
4818 return 0;
4821 /*****************************************************************************
4822 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4824 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4825 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4827 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4828 pDevModeOutput, pDevModeInput);
4829 return 0;
4832 /*****************************************************************************
4833 * PrinterProperties [WINSPOOL.@]
4835 * Displays a dialog to set the properties of the printer.
4837 * RETURNS
4838 * nonzero on success or zero on failure
4840 * BUGS
4841 * implemented as stub only
4843 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4844 HANDLE hPrinter /* [in] handle to printer object */
4846 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4847 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4848 return FALSE;
4851 /*****************************************************************************
4852 * EnumJobsA [WINSPOOL.@]
4855 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4856 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4857 LPDWORD pcReturned)
4859 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4860 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4862 if(pcbNeeded) *pcbNeeded = 0;
4863 if(pcReturned) *pcReturned = 0;
4864 return FALSE;
4868 /*****************************************************************************
4869 * EnumJobsW [WINSPOOL.@]
4872 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4873 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4874 LPDWORD pcReturned)
4876 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4877 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4879 if(pcbNeeded) *pcbNeeded = 0;
4880 if(pcReturned) *pcReturned = 0;
4881 return FALSE;
4884 /*****************************************************************************
4885 * WINSPOOL_EnumPrinterDrivers [internal]
4887 * Delivers information about all printer drivers installed on the
4888 * localhost or a given server
4890 * RETURNS
4891 * nonzero on success or zero on failure. If the buffer for the returned
4892 * information is too small the function will return an error
4894 * BUGS
4895 * - only implemented for localhost, foreign hosts will return an error
4897 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4898 DWORD Level, LPBYTE pDriverInfo,
4899 DWORD cbBuf, LPDWORD pcbNeeded,
4900 LPDWORD pcReturned, BOOL unicode)
4902 { HKEY hkeyDrivers;
4903 DWORD i, needed, number = 0, size = 0;
4904 WCHAR DriverNameW[255];
4905 PBYTE ptr;
4906 const printenv_t * env;
4908 TRACE("%s,%s,%d,%p,%d,%d\n",
4909 debugstr_w(pName), debugstr_w(pEnvironment),
4910 Level, pDriverInfo, cbBuf, unicode);
4912 /* check for local drivers */
4913 if((pName) && (pName[0])) {
4914 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4915 SetLastError(ERROR_ACCESS_DENIED);
4916 return FALSE;
4919 env = validate_envW(pEnvironment);
4920 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4922 /* check input parameter */
4923 if((Level < 1) || (Level > 3)) {
4924 ERR("unsupported level %d\n", Level);
4925 SetLastError(ERROR_INVALID_LEVEL);
4926 return FALSE;
4929 /* initialize return values */
4930 if(pDriverInfo)
4931 memset( pDriverInfo, 0, cbBuf);
4932 *pcbNeeded = 0;
4933 *pcReturned = 0;
4935 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
4936 if(!hkeyDrivers) {
4937 ERR("Can't open Drivers key\n");
4938 return FALSE;
4941 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
4942 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4943 RegCloseKey(hkeyDrivers);
4944 ERR("Can't query Drivers key\n");
4945 return FALSE;
4947 TRACE("Found %d Drivers\n", number);
4949 /* get size of single struct
4950 * unicode and ascii structure have the same size
4952 switch (Level) {
4953 case 1:
4954 size = sizeof(DRIVER_INFO_1A);
4955 break;
4956 case 2:
4957 size = sizeof(DRIVER_INFO_2A);
4958 break;
4959 case 3:
4960 size = sizeof(DRIVER_INFO_3A);
4961 break;
4964 /* calculate required buffer size */
4965 *pcbNeeded = size * number;
4967 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
4968 i < number;
4969 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
4970 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
4971 != ERROR_SUCCESS) {
4972 ERR("Can't enum key number %d\n", i);
4973 RegCloseKey(hkeyDrivers);
4974 return FALSE;
4976 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4977 env, Level, ptr,
4978 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
4979 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4980 &needed, unicode)) {
4981 RegCloseKey(hkeyDrivers);
4982 return FALSE;
4984 (*pcbNeeded) += needed;
4987 RegCloseKey(hkeyDrivers);
4989 if(cbBuf < *pcbNeeded){
4990 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4991 return FALSE;
4994 *pcReturned = number;
4995 return TRUE;
4998 /*****************************************************************************
4999 * EnumPrinterDriversW [WINSPOOL.@]
5001 * see function EnumPrinterDrivers for RETURNS, BUGS
5003 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5004 LPBYTE pDriverInfo, DWORD cbBuf,
5005 LPDWORD pcbNeeded, LPDWORD pcReturned)
5007 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5008 cbBuf, pcbNeeded, pcReturned, TRUE);
5011 /*****************************************************************************
5012 * EnumPrinterDriversA [WINSPOOL.@]
5014 * see function EnumPrinterDrivers for RETURNS, BUGS
5016 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5017 LPBYTE pDriverInfo, DWORD cbBuf,
5018 LPDWORD pcbNeeded, LPDWORD pcReturned)
5019 { BOOL ret;
5020 UNICODE_STRING pNameW, pEnvironmentW;
5021 PWSTR pwstrNameW, pwstrEnvironmentW;
5023 pwstrNameW = asciitounicode(&pNameW, pName);
5024 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5026 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5027 Level, pDriverInfo, cbBuf, pcbNeeded,
5028 pcReturned, FALSE);
5029 RtlFreeUnicodeString(&pNameW);
5030 RtlFreeUnicodeString(&pEnvironmentW);
5032 return ret;
5035 /******************************************************************************
5036 * EnumPortsA (WINSPOOL.@)
5038 * See EnumPortsW.
5041 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5042 LPDWORD pcbNeeded, LPDWORD pcReturned)
5044 BOOL res;
5045 LPBYTE bufferW = NULL;
5046 LPWSTR nameW = NULL;
5047 DWORD needed = 0;
5048 DWORD numentries = 0;
5049 INT len;
5051 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5052 cbBuf, pcbNeeded, pcReturned);
5054 /* convert servername to unicode */
5055 if (pName) {
5056 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5057 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5058 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5060 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5061 needed = cbBuf * sizeof(WCHAR);
5062 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5063 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5065 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5066 if (pcbNeeded) needed = *pcbNeeded;
5067 /* HeapReAlloc return NULL, when bufferW was NULL */
5068 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5069 HeapAlloc(GetProcessHeap(), 0, needed);
5071 /* Try again with the large Buffer */
5072 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5074 needed = pcbNeeded ? *pcbNeeded : 0;
5075 numentries = pcReturned ? *pcReturned : 0;
5078 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5079 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5081 if (res) {
5082 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5083 DWORD entrysize = 0;
5084 DWORD index;
5085 LPSTR ptr;
5086 LPPORT_INFO_2W pi2w;
5087 LPPORT_INFO_2A pi2a;
5089 needed = 0;
5090 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5092 /* First pass: calculate the size for all Entries */
5093 pi2w = (LPPORT_INFO_2W) bufferW;
5094 pi2a = (LPPORT_INFO_2A) pPorts;
5095 index = 0;
5096 while (index < numentries) {
5097 index++;
5098 needed += entrysize; /* PORT_INFO_?A */
5099 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5101 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5102 NULL, 0, NULL, NULL);
5103 if (Level > 1) {
5104 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5105 NULL, 0, NULL, NULL);
5106 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5107 NULL, 0, NULL, NULL);
5109 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5110 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5111 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5114 /* check for errors and quit on failure */
5115 if (cbBuf < needed) {
5116 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5117 res = FALSE;
5118 goto cleanup;
5120 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5121 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5122 cbBuf -= len ; /* free Bytes in the user-Buffer */
5123 pi2w = (LPPORT_INFO_2W) bufferW;
5124 pi2a = (LPPORT_INFO_2A) pPorts;
5125 index = 0;
5126 /* Second Pass: Fill the User Buffer (if we have one) */
5127 while ((index < numentries) && pPorts) {
5128 index++;
5129 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5130 pi2a->pPortName = ptr;
5131 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5132 ptr, cbBuf , NULL, NULL);
5133 ptr += len;
5134 cbBuf -= len;
5135 if (Level > 1) {
5136 pi2a->pMonitorName = ptr;
5137 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5138 ptr, cbBuf, NULL, NULL);
5139 ptr += len;
5140 cbBuf -= len;
5142 pi2a->pDescription = ptr;
5143 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5144 ptr, cbBuf, NULL, NULL);
5145 ptr += len;
5146 cbBuf -= len;
5148 pi2a->fPortType = pi2w->fPortType;
5149 pi2a->Reserved = 0; /* documented: "must be zero" */
5152 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5153 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5154 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5158 cleanup:
5159 if (pcbNeeded) *pcbNeeded = needed;
5160 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5162 HeapFree(GetProcessHeap(), 0, nameW);
5163 HeapFree(GetProcessHeap(), 0, bufferW);
5165 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5166 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5168 return (res);
5172 /******************************************************************************
5173 * EnumPortsW (WINSPOOL.@)
5175 * Enumerate available Ports
5177 * PARAMS
5178 * name [I] Servername or NULL (local Computer)
5179 * level [I] Structure-Level (1 or 2)
5180 * buffer [O] PTR to Buffer that receives the Result
5181 * bufsize [I] Size of Buffer at buffer
5182 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5183 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5185 * RETURNS
5186 * Success: TRUE
5187 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5191 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5193 DWORD needed = 0;
5194 DWORD numentries = 0;
5195 BOOL res = FALSE;
5197 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5198 cbBuf, pcbNeeded, pcReturned);
5200 if (pName && (pName[0])) {
5201 FIXME("not implemented for Server %s\n", debugstr_w(pName));
5202 SetLastError(ERROR_ACCESS_DENIED);
5203 goto emP_cleanup;
5206 /* Level is not checked in win9x */
5207 if (!Level || (Level > 2)) {
5208 WARN("level (%d) is ignored in win9x\n", Level);
5209 SetLastError(ERROR_INVALID_LEVEL);
5210 goto emP_cleanup;
5212 if (!pcbNeeded) {
5213 SetLastError(RPC_X_NULL_REF_POINTER);
5214 goto emP_cleanup;
5217 EnterCriticalSection(&monitor_handles_cs);
5218 monitor_loadall();
5220 /* Scan all local Ports */
5221 numentries = 0;
5222 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
5224 /* we calculated the needed buffersize. now do the error-checks */
5225 if (cbBuf < needed) {
5226 monitor_unloadall();
5227 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5228 goto emP_cleanup_cs;
5230 else if (!pPorts || !pcReturned) {
5231 monitor_unloadall();
5232 SetLastError(RPC_X_NULL_REF_POINTER);
5233 goto emP_cleanup_cs;
5236 /* Fill the Buffer */
5237 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
5238 res = TRUE;
5239 monitor_unloadall();
5241 emP_cleanup_cs:
5242 LeaveCriticalSection(&monitor_handles_cs);
5244 emP_cleanup:
5245 if (pcbNeeded) *pcbNeeded = needed;
5246 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5248 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5249 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5251 return (res);
5254 /******************************************************************************
5255 * GetDefaultPrinterW (WINSPOOL.@)
5257 * FIXME
5258 * This function must read the value from data 'device' of key
5259 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5261 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5263 BOOL retval = TRUE;
5264 DWORD insize, len;
5265 WCHAR *buffer, *ptr;
5267 if (!namesize)
5269 SetLastError(ERROR_INVALID_PARAMETER);
5270 return FALSE;
5273 /* make the buffer big enough for the stuff from the profile/registry,
5274 * the content must fit into the local buffer to compute the correct
5275 * size even if the extern buffer is too small or not given.
5276 * (20 for ,driver,port) */
5277 insize = *namesize;
5278 len = max(100, (insize + 20));
5279 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5281 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5283 SetLastError (ERROR_FILE_NOT_FOUND);
5284 retval = FALSE;
5285 goto end;
5287 TRACE("%s\n", debugstr_w(buffer));
5289 if ((ptr = strchrW(buffer, ',')) == NULL)
5291 SetLastError(ERROR_INVALID_NAME);
5292 retval = FALSE;
5293 goto end;
5296 *ptr = 0;
5297 *namesize = strlenW(buffer) + 1;
5298 if(!name || (*namesize > insize))
5300 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5301 retval = FALSE;
5302 goto end;
5304 strcpyW(name, buffer);
5306 end:
5307 HeapFree( GetProcessHeap(), 0, buffer);
5308 return retval;
5312 /******************************************************************************
5313 * GetDefaultPrinterA (WINSPOOL.@)
5315 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5317 BOOL retval = TRUE;
5318 DWORD insize = 0;
5319 WCHAR *bufferW = NULL;
5321 if (!namesize)
5323 SetLastError(ERROR_INVALID_PARAMETER);
5324 return FALSE;
5327 if(name && *namesize) {
5328 insize = *namesize;
5329 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5332 if(!GetDefaultPrinterW( bufferW, namesize)) {
5333 retval = FALSE;
5334 goto end;
5337 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5338 NULL, NULL);
5339 if (!*namesize)
5341 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5342 retval = FALSE;
5344 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5346 end:
5347 HeapFree( GetProcessHeap(), 0, bufferW);
5348 return retval;
5352 /******************************************************************************
5353 * SetDefaultPrinterW (WINSPOOL.204)
5355 * Set the Name of the Default Printer
5357 * PARAMS
5358 * pszPrinter [I] Name of the Printer or NULL
5360 * RETURNS
5361 * Success: True
5362 * Failure: FALSE
5364 * NOTES
5365 * When the Parameter is NULL or points to an Empty String and
5366 * a Default Printer was already present, then this Function changes nothing.
5367 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5368 * the First enumerated local Printer is used.
5371 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5374 TRACE("(%s)\n", debugstr_w(pszPrinter));
5376 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5377 return FALSE;
5380 /******************************************************************************
5381 * SetDefaultPrinterA (WINSPOOL.202)
5383 * See SetDefaultPrinterW.
5386 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5389 TRACE("(%s)\n", debugstr_a(pszPrinter));
5391 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5392 return FALSE;
5396 /******************************************************************************
5397 * SetPrinterDataExA (WINSPOOL.@)
5399 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5400 LPCSTR pValueName, DWORD Type,
5401 LPBYTE pData, DWORD cbData)
5403 HKEY hkeyPrinter, hkeySubkey;
5404 DWORD ret;
5406 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5407 debugstr_a(pValueName), Type, pData, cbData);
5409 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5410 != ERROR_SUCCESS)
5411 return ret;
5413 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5414 != ERROR_SUCCESS) {
5415 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5416 RegCloseKey(hkeyPrinter);
5417 return ret;
5419 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5420 RegCloseKey(hkeySubkey);
5421 RegCloseKey(hkeyPrinter);
5422 return ret;
5425 /******************************************************************************
5426 * SetPrinterDataExW (WINSPOOL.@)
5428 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5429 LPCWSTR pValueName, DWORD Type,
5430 LPBYTE pData, DWORD cbData)
5432 HKEY hkeyPrinter, hkeySubkey;
5433 DWORD ret;
5435 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5436 debugstr_w(pValueName), Type, pData, cbData);
5438 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5439 != ERROR_SUCCESS)
5440 return ret;
5442 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5443 != ERROR_SUCCESS) {
5444 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5445 RegCloseKey(hkeyPrinter);
5446 return ret;
5448 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5449 RegCloseKey(hkeySubkey);
5450 RegCloseKey(hkeyPrinter);
5451 return ret;
5454 /******************************************************************************
5455 * SetPrinterDataA (WINSPOOL.@)
5457 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5458 LPBYTE pData, DWORD cbData)
5460 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5461 pData, cbData);
5464 /******************************************************************************
5465 * SetPrinterDataW (WINSPOOL.@)
5467 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5468 LPBYTE pData, DWORD cbData)
5470 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5471 pData, cbData);
5474 /******************************************************************************
5475 * GetPrinterDataExA (WINSPOOL.@)
5477 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5478 LPCSTR pValueName, LPDWORD pType,
5479 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5481 HKEY hkeyPrinter, hkeySubkey;
5482 DWORD ret;
5484 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5485 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5486 pcbNeeded);
5488 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5489 != ERROR_SUCCESS)
5490 return ret;
5492 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5493 != ERROR_SUCCESS) {
5494 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5495 RegCloseKey(hkeyPrinter);
5496 return ret;
5498 *pcbNeeded = nSize;
5499 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5500 RegCloseKey(hkeySubkey);
5501 RegCloseKey(hkeyPrinter);
5502 return ret;
5505 /******************************************************************************
5506 * GetPrinterDataExW (WINSPOOL.@)
5508 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5509 LPCWSTR pValueName, LPDWORD pType,
5510 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5512 HKEY hkeyPrinter, hkeySubkey;
5513 DWORD ret;
5515 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5516 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5517 pcbNeeded);
5519 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5520 != ERROR_SUCCESS)
5521 return ret;
5523 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5524 != ERROR_SUCCESS) {
5525 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5526 RegCloseKey(hkeyPrinter);
5527 return ret;
5529 *pcbNeeded = nSize;
5530 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5531 RegCloseKey(hkeySubkey);
5532 RegCloseKey(hkeyPrinter);
5533 return ret;
5536 /******************************************************************************
5537 * GetPrinterDataA (WINSPOOL.@)
5539 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5540 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5542 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5543 pData, nSize, pcbNeeded);
5546 /******************************************************************************
5547 * GetPrinterDataW (WINSPOOL.@)
5549 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5550 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5552 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5553 pData, nSize, pcbNeeded);
5556 /*******************************************************************************
5557 * EnumPrinterDataExW [WINSPOOL.@]
5559 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5560 LPBYTE pEnumValues, DWORD cbEnumValues,
5561 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5563 HKEY hkPrinter, hkSubKey;
5564 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5565 cbValueNameLen, cbMaxValueLen, cbValueLen,
5566 cbBufSize, dwType;
5567 LPWSTR lpValueName;
5568 HANDLE hHeap;
5569 PBYTE lpValue;
5570 PPRINTER_ENUM_VALUESW ppev;
5572 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5574 if (pKeyName == NULL || *pKeyName == 0)
5575 return ERROR_INVALID_PARAMETER;
5577 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5578 if (ret != ERROR_SUCCESS)
5580 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5581 hPrinter, ret);
5582 return ret;
5585 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5586 if (ret != ERROR_SUCCESS)
5588 r = RegCloseKey (hkPrinter);
5589 if (r != ERROR_SUCCESS)
5590 WARN ("RegCloseKey returned %i\n", r);
5591 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5592 debugstr_w (pKeyName), ret);
5593 return ret;
5596 ret = RegCloseKey (hkPrinter);
5597 if (ret != ERROR_SUCCESS)
5599 ERR ("RegCloseKey returned %i\n", ret);
5600 r = RegCloseKey (hkSubKey);
5601 if (r != ERROR_SUCCESS)
5602 WARN ("RegCloseKey returned %i\n", r);
5603 return ret;
5606 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5607 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5608 if (ret != ERROR_SUCCESS)
5610 r = RegCloseKey (hkSubKey);
5611 if (r != ERROR_SUCCESS)
5612 WARN ("RegCloseKey returned %i\n", r);
5613 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5614 return ret;
5617 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5618 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5620 if (cValues == 0) /* empty key */
5622 r = RegCloseKey (hkSubKey);
5623 if (r != ERROR_SUCCESS)
5624 WARN ("RegCloseKey returned %i\n", r);
5625 *pcbEnumValues = *pnEnumValues = 0;
5626 return ERROR_SUCCESS;
5629 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5631 hHeap = GetProcessHeap ();
5632 if (hHeap == NULL)
5634 ERR ("GetProcessHeap failed\n");
5635 r = RegCloseKey (hkSubKey);
5636 if (r != ERROR_SUCCESS)
5637 WARN ("RegCloseKey returned %i\n", r);
5638 return ERROR_OUTOFMEMORY;
5641 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5642 if (lpValueName == NULL)
5644 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5645 r = RegCloseKey (hkSubKey);
5646 if (r != ERROR_SUCCESS)
5647 WARN ("RegCloseKey returned %i\n", r);
5648 return ERROR_OUTOFMEMORY;
5651 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5652 if (lpValue == NULL)
5654 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5655 if (HeapFree (hHeap, 0, lpValueName) == 0)
5656 WARN ("HeapFree failed with code %i\n", GetLastError ());
5657 r = RegCloseKey (hkSubKey);
5658 if (r != ERROR_SUCCESS)
5659 WARN ("RegCloseKey returned %i\n", r);
5660 return ERROR_OUTOFMEMORY;
5663 TRACE ("pass 1: calculating buffer required for all names and values\n");
5665 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5667 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5669 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5671 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5672 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5673 NULL, NULL, lpValue, &cbValueLen);
5674 if (ret != ERROR_SUCCESS)
5676 if (HeapFree (hHeap, 0, lpValue) == 0)
5677 WARN ("HeapFree failed with code %i\n", GetLastError ());
5678 if (HeapFree (hHeap, 0, lpValueName) == 0)
5679 WARN ("HeapFree failed with code %i\n", GetLastError ());
5680 r = RegCloseKey (hkSubKey);
5681 if (r != ERROR_SUCCESS)
5682 WARN ("RegCloseKey returned %i\n", r);
5683 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5684 return ret;
5687 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5688 debugstr_w (lpValueName), dwIndex,
5689 cbValueNameLen + 1, cbValueLen);
5691 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5692 cbBufSize += cbValueLen;
5695 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5697 *pcbEnumValues = cbBufSize;
5698 *pnEnumValues = cValues;
5700 if (cbEnumValues < cbBufSize) /* buffer too small */
5702 if (HeapFree (hHeap, 0, lpValue) == 0)
5703 WARN ("HeapFree failed with code %i\n", GetLastError ());
5704 if (HeapFree (hHeap, 0, lpValueName) == 0)
5705 WARN ("HeapFree failed with code %i\n", GetLastError ());
5706 r = RegCloseKey (hkSubKey);
5707 if (r != ERROR_SUCCESS)
5708 WARN ("RegCloseKey returned %i\n", r);
5709 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5710 return ERROR_MORE_DATA;
5713 TRACE ("pass 2: copying all names and values to buffer\n");
5715 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5716 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5718 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5720 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5721 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5722 NULL, &dwType, lpValue, &cbValueLen);
5723 if (ret != ERROR_SUCCESS)
5725 if (HeapFree (hHeap, 0, lpValue) == 0)
5726 WARN ("HeapFree failed with code %i\n", GetLastError ());
5727 if (HeapFree (hHeap, 0, lpValueName) == 0)
5728 WARN ("HeapFree failed with code %i\n", GetLastError ());
5729 r = RegCloseKey (hkSubKey);
5730 if (r != ERROR_SUCCESS)
5731 WARN ("RegCloseKey returned %i\n", r);
5732 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5733 return ret;
5736 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5737 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5738 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5739 pEnumValues += cbValueNameLen;
5741 /* return # of *bytes* (including trailing \0), not # of chars */
5742 ppev[dwIndex].cbValueName = cbValueNameLen;
5744 ppev[dwIndex].dwType = dwType;
5746 memcpy (pEnumValues, lpValue, cbValueLen);
5747 ppev[dwIndex].pData = pEnumValues;
5748 pEnumValues += cbValueLen;
5750 ppev[dwIndex].cbData = cbValueLen;
5752 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5753 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5756 if (HeapFree (hHeap, 0, lpValue) == 0)
5758 ret = GetLastError ();
5759 ERR ("HeapFree failed with code %i\n", ret);
5760 if (HeapFree (hHeap, 0, lpValueName) == 0)
5761 WARN ("HeapFree failed with code %i\n", GetLastError ());
5762 r = RegCloseKey (hkSubKey);
5763 if (r != ERROR_SUCCESS)
5764 WARN ("RegCloseKey returned %i\n", r);
5765 return ret;
5768 if (HeapFree (hHeap, 0, lpValueName) == 0)
5770 ret = GetLastError ();
5771 ERR ("HeapFree failed with code %i\n", ret);
5772 r = RegCloseKey (hkSubKey);
5773 if (r != ERROR_SUCCESS)
5774 WARN ("RegCloseKey returned %i\n", r);
5775 return ret;
5778 ret = RegCloseKey (hkSubKey);
5779 if (ret != ERROR_SUCCESS)
5781 ERR ("RegCloseKey returned %i\n", ret);
5782 return ret;
5785 return ERROR_SUCCESS;
5788 /*******************************************************************************
5789 * EnumPrinterDataExA [WINSPOOL.@]
5791 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5792 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5793 * what Windows 2000 SP1 does.
5796 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5797 LPBYTE pEnumValues, DWORD cbEnumValues,
5798 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5800 INT len;
5801 LPWSTR pKeyNameW;
5802 DWORD ret, dwIndex, dwBufSize;
5803 HANDLE hHeap;
5804 LPSTR pBuffer;
5806 TRACE ("%p %s\n", hPrinter, pKeyName);
5808 if (pKeyName == NULL || *pKeyName == 0)
5809 return ERROR_INVALID_PARAMETER;
5811 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5812 if (len == 0)
5814 ret = GetLastError ();
5815 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5816 return ret;
5819 hHeap = GetProcessHeap ();
5820 if (hHeap == NULL)
5822 ERR ("GetProcessHeap failed\n");
5823 return ERROR_OUTOFMEMORY;
5826 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5827 if (pKeyNameW == NULL)
5829 ERR ("Failed to allocate %i bytes from process heap\n",
5830 (LONG)(len * sizeof (WCHAR)));
5831 return ERROR_OUTOFMEMORY;
5834 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5836 ret = GetLastError ();
5837 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5838 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5839 WARN ("HeapFree failed with code %i\n", GetLastError ());
5840 return ret;
5843 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5844 pcbEnumValues, pnEnumValues);
5845 if (ret != ERROR_SUCCESS)
5847 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5848 WARN ("HeapFree failed with code %i\n", GetLastError ());
5849 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5850 return ret;
5853 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5855 ret = GetLastError ();
5856 ERR ("HeapFree failed with code %i\n", ret);
5857 return ret;
5860 if (*pnEnumValues == 0) /* empty key */
5861 return ERROR_SUCCESS;
5863 dwBufSize = 0;
5864 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5866 PPRINTER_ENUM_VALUESW ppev =
5867 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5869 if (dwBufSize < ppev->cbValueName)
5870 dwBufSize = ppev->cbValueName;
5872 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5873 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5874 dwBufSize = ppev->cbData;
5877 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5879 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5880 if (pBuffer == NULL)
5882 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5883 return ERROR_OUTOFMEMORY;
5886 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5888 PPRINTER_ENUM_VALUESW ppev =
5889 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5891 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5892 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5893 NULL);
5894 if (len == 0)
5896 ret = GetLastError ();
5897 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5898 if (HeapFree (hHeap, 0, pBuffer) == 0)
5899 WARN ("HeapFree failed with code %i\n", GetLastError ());
5900 return ret;
5903 memcpy (ppev->pValueName, pBuffer, len);
5905 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5907 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5908 ppev->dwType != REG_MULTI_SZ)
5909 continue;
5911 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5912 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5913 if (len == 0)
5915 ret = GetLastError ();
5916 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5917 if (HeapFree (hHeap, 0, pBuffer) == 0)
5918 WARN ("HeapFree failed with code %i\n", GetLastError ());
5919 return ret;
5922 memcpy (ppev->pData, pBuffer, len);
5924 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5925 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5928 if (HeapFree (hHeap, 0, pBuffer) == 0)
5930 ret = GetLastError ();
5931 ERR ("HeapFree failed with code %i\n", ret);
5932 return ret;
5935 return ERROR_SUCCESS;
5938 /******************************************************************************
5939 * AbortPrinter (WINSPOOL.@)
5941 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5943 FIXME("(%p), stub!\n", hPrinter);
5944 return TRUE;
5947 /******************************************************************************
5948 * AddPortA (WINSPOOL.@)
5950 * See AddPortW.
5953 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5955 LPWSTR nameW = NULL;
5956 LPWSTR monitorW = NULL;
5957 DWORD len;
5958 BOOL res;
5960 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
5962 if (pName) {
5963 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5964 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5965 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5968 if (pMonitorName) {
5969 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5970 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5971 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5973 res = AddPortW(nameW, hWnd, monitorW);
5974 HeapFree(GetProcessHeap(), 0, nameW);
5975 HeapFree(GetProcessHeap(), 0, monitorW);
5976 return res;
5979 /******************************************************************************
5980 * AddPortW (WINSPOOL.@)
5982 * Add a Port for a specific Monitor
5984 * PARAMS
5985 * pName [I] Servername or NULL (local Computer)
5986 * hWnd [I] Handle to parent Window for the Dialog-Box
5987 * pMonitorName [I] Name of the Monitor that manage the Port
5989 * RETURNS
5990 * Success: TRUE
5991 * Failure: FALSE
5994 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5996 monitor_t * pm;
5997 monitor_t * pui;
5998 DWORD res;
6000 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6002 if (pName && pName[0]) {
6003 SetLastError(ERROR_INVALID_PARAMETER);
6004 return FALSE;
6007 if (!pMonitorName) {
6008 SetLastError(RPC_X_NULL_REF_POINTER);
6009 return FALSE;
6012 /* an empty Monitorname is Invalid */
6013 if (!pMonitorName[0]) {
6014 SetLastError(ERROR_NOT_SUPPORTED);
6015 return FALSE;
6018 pm = monitor_load(pMonitorName, NULL);
6019 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
6020 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
6021 TRACE("got %d with %u\n", res, GetLastError());
6022 res = TRUE;
6024 else
6026 pui = monitor_loadui(pm);
6027 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
6028 TRACE("use %p: %s\n", pui, debugstr_w(pui->dllname));
6029 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
6030 TRACE("got %d with %u\n", res, GetLastError());
6031 res = TRUE;
6033 else
6035 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName),
6036 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6038 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6039 SetLastError(ERROR_NOT_SUPPORTED);
6040 res = FALSE;
6042 monitor_unload(pui);
6044 monitor_unload(pm);
6045 TRACE("returning %d with %u\n", res, GetLastError());
6046 return res;
6049 /******************************************************************************
6050 * AddPortExA (WINSPOOL.@)
6052 * See AddPortExW.
6055 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6057 PORT_INFO_2W pi2W;
6058 PORT_INFO_2A * pi2A;
6059 LPWSTR nameW = NULL;
6060 LPWSTR monitorW = NULL;
6061 DWORD len;
6062 BOOL res;
6064 pi2A = (PORT_INFO_2A *) pBuffer;
6066 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6067 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6069 if ((level < 1) || (level > 2)) {
6070 SetLastError(ERROR_INVALID_LEVEL);
6071 return FALSE;
6074 if (!pi2A) {
6075 SetLastError(ERROR_INVALID_PARAMETER);
6076 return FALSE;
6079 if (pName) {
6080 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6081 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6082 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6085 if (pMonitorName) {
6086 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6087 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6088 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6091 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6093 if (pi2A->pPortName) {
6094 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6095 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6096 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6099 if (level > 1) {
6100 if (pi2A->pMonitorName) {
6101 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6102 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6103 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6106 if (pi2A->pDescription) {
6107 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6108 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6109 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6111 pi2W.fPortType = pi2A->fPortType;
6112 pi2W.Reserved = pi2A->Reserved;
6115 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6117 HeapFree(GetProcessHeap(), 0, nameW);
6118 HeapFree(GetProcessHeap(), 0, monitorW);
6119 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6120 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6121 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6122 return res;
6126 /******************************************************************************
6127 * AddPortExW (WINSPOOL.@)
6129 * Add a Port for a specific Monitor, without presenting a user interface
6131 * PARAMS
6132 * pName [I] Servername or NULL (local Computer)
6133 * level [I] Structure-Level (1 or 2) for pBuffer
6134 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6135 * pMonitorName [I] Name of the Monitor that manage the Port
6137 * RETURNS
6138 * Success: TRUE
6139 * Failure: FALSE
6142 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6144 PORT_INFO_2W * pi2;
6145 monitor_t * pm;
6146 DWORD res = FALSE;
6148 pi2 = (PORT_INFO_2W *) pBuffer;
6150 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6151 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6152 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6153 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6156 if ((level < 1) || (level > 2)) {
6157 SetLastError(ERROR_INVALID_LEVEL);
6158 return FALSE;
6161 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6162 SetLastError(ERROR_INVALID_PARAMETER);
6163 return FALSE;
6166 /* load the Monitor */
6167 pm = monitor_load(pMonitorName, NULL);
6168 if (!pm) {
6169 SetLastError(ERROR_INVALID_PARAMETER);
6170 return FALSE;
6173 if (pm->monitor && pm->monitor->pfnAddPortEx) {
6174 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
6175 TRACE("got %u with %u\n", res, GetLastError());
6177 else
6179 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName), pm->monitor);
6181 monitor_unload(pm);
6182 return res;
6185 /******************************************************************************
6186 * AddPrinterConnectionA (WINSPOOL.@)
6188 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6190 FIXME("%s\n", debugstr_a(pName));
6191 return FALSE;
6194 /******************************************************************************
6195 * AddPrinterConnectionW (WINSPOOL.@)
6197 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6199 FIXME("%s\n", debugstr_w(pName));
6200 return FALSE;
6203 /******************************************************************************
6204 * AddPrinterDriverExW (WINSPOOL.@)
6206 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
6207 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6209 FIXME("%s %d %p %d\n", debugstr_w(pName),
6210 Level, pDriverInfo, dwFileCopyFlags);
6211 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
6212 return FALSE;
6215 /******************************************************************************
6216 * AddPrinterDriverExA (WINSPOOL.@)
6218 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
6219 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6221 FIXME("%s %d %p %d\n", debugstr_a(pName),
6222 Level, pDriverInfo, dwFileCopyFlags);
6223 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
6224 return FALSE;
6227 /******************************************************************************
6228 * ConfigurePortA (WINSPOOL.@)
6230 * See ConfigurePortW.
6233 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6235 LPWSTR nameW = NULL;
6236 LPWSTR portW = NULL;
6237 INT len;
6238 DWORD res;
6240 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6242 /* convert servername to unicode */
6243 if (pName) {
6244 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6245 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6246 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6249 /* convert portname to unicode */
6250 if (pPortName) {
6251 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6252 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6253 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6256 res = ConfigurePortW(nameW, hWnd, portW);
6257 HeapFree(GetProcessHeap(), 0, nameW);
6258 HeapFree(GetProcessHeap(), 0, portW);
6259 return res;
6262 /******************************************************************************
6263 * ConfigurePortW (WINSPOOL.@)
6265 * Display the Configuration-Dialog for a specific Port
6267 * PARAMS
6268 * pName [I] Servername or NULL (local Computer)
6269 * hWnd [I] Handle to parent Window for the Dialog-Box
6270 * pPortName [I] Name of the Port, that should be configured
6272 * RETURNS
6273 * Success: TRUE
6274 * Failure: FALSE
6277 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6279 monitor_t * pm;
6280 monitor_t * pui;
6281 DWORD res;
6283 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6285 if (pName && pName[0]) {
6286 SetLastError(ERROR_INVALID_PARAMETER);
6287 return FALSE;
6290 if (!pPortName) {
6291 SetLastError(RPC_X_NULL_REF_POINTER);
6292 return FALSE;
6295 /* an empty Portname is Invalid, but can popup a Dialog */
6296 if (!pPortName[0]) {
6297 SetLastError(ERROR_NOT_SUPPORTED);
6298 return FALSE;
6301 pm = monitor_load_by_port(pPortName);
6302 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6303 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6304 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6305 TRACE("got %d with %u\n", res, GetLastError());
6307 else
6309 pui = monitor_loadui(pm);
6310 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6311 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6312 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6313 TRACE("got %d with %u\n", res, GetLastError());
6315 else
6317 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6318 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6320 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6321 SetLastError(ERROR_NOT_SUPPORTED);
6322 res = FALSE;
6324 monitor_unload(pui);
6326 monitor_unload(pm);
6328 TRACE("returning %d with %u\n", res, GetLastError());
6329 return res;
6332 /******************************************************************************
6333 * ConnectToPrinterDlg (WINSPOOL.@)
6335 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6337 FIXME("%p %x\n", hWnd, Flags);
6338 return NULL;
6341 /******************************************************************************
6342 * DeletePrinterConnectionA (WINSPOOL.@)
6344 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6346 FIXME("%s\n", debugstr_a(pName));
6347 return TRUE;
6350 /******************************************************************************
6351 * DeletePrinterConnectionW (WINSPOOL.@)
6353 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6355 FIXME("%s\n", debugstr_w(pName));
6356 return TRUE;
6359 /******************************************************************************
6360 * DeletePrinterDriverExW (WINSPOOL.@)
6362 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6363 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6365 HKEY hkey_drivers;
6366 BOOL ret = FALSE;
6368 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6369 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6371 if(pName && pName[0])
6373 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6374 SetLastError(ERROR_INVALID_PARAMETER);
6375 return FALSE;
6378 if(dwDeleteFlag)
6380 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6381 SetLastError(ERROR_INVALID_PARAMETER);
6382 return FALSE;
6385 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6387 if(!hkey_drivers)
6389 ERR("Can't open drivers key\n");
6390 return FALSE;
6393 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6394 ret = TRUE;
6396 RegCloseKey(hkey_drivers);
6398 return ret;
6401 /******************************************************************************
6402 * DeletePrinterDriverExA (WINSPOOL.@)
6404 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6405 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6407 UNICODE_STRING NameW, EnvW, DriverW;
6408 BOOL ret;
6410 asciitounicode(&NameW, pName);
6411 asciitounicode(&EnvW, pEnvironment);
6412 asciitounicode(&DriverW, pDriverName);
6414 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6416 RtlFreeUnicodeString(&DriverW);
6417 RtlFreeUnicodeString(&EnvW);
6418 RtlFreeUnicodeString(&NameW);
6420 return ret;
6423 /******************************************************************************
6424 * DeletePrinterDataExW (WINSPOOL.@)
6426 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6427 LPCWSTR pValueName)
6429 FIXME("%p %s %s\n", hPrinter,
6430 debugstr_w(pKeyName), debugstr_w(pValueName));
6431 return ERROR_INVALID_PARAMETER;
6434 /******************************************************************************
6435 * DeletePrinterDataExA (WINSPOOL.@)
6437 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6438 LPCSTR pValueName)
6440 FIXME("%p %s %s\n", hPrinter,
6441 debugstr_a(pKeyName), debugstr_a(pValueName));
6442 return ERROR_INVALID_PARAMETER;
6445 /******************************************************************************
6446 * DeletePrintProcessorA (WINSPOOL.@)
6448 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6450 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6451 debugstr_a(pPrintProcessorName));
6452 return TRUE;
6455 /******************************************************************************
6456 * DeletePrintProcessorW (WINSPOOL.@)
6458 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6460 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6461 debugstr_w(pPrintProcessorName));
6462 return TRUE;
6465 /******************************************************************************
6466 * DeletePrintProvidorA (WINSPOOL.@)
6468 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6470 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6471 debugstr_a(pPrintProviderName));
6472 return TRUE;
6475 /******************************************************************************
6476 * DeletePrintProvidorW (WINSPOOL.@)
6478 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6480 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6481 debugstr_w(pPrintProviderName));
6482 return TRUE;
6485 /******************************************************************************
6486 * EnumFormsA (WINSPOOL.@)
6488 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6489 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6491 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6492 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6493 return FALSE;
6496 /******************************************************************************
6497 * EnumFormsW (WINSPOOL.@)
6499 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6500 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6502 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6503 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6504 return FALSE;
6507 /*****************************************************************************
6508 * EnumMonitorsA [WINSPOOL.@]
6510 * See EnumMonitorsW.
6513 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6514 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6516 BOOL res;
6517 LPBYTE bufferW = NULL;
6518 LPWSTR nameW = NULL;
6519 DWORD needed = 0;
6520 DWORD numentries = 0;
6521 INT len;
6523 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6524 cbBuf, pcbNeeded, pcReturned);
6526 /* convert servername to unicode */
6527 if (pName) {
6528 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6529 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6530 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6532 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6533 needed = cbBuf * sizeof(WCHAR);
6534 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6535 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6537 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6538 if (pcbNeeded) needed = *pcbNeeded;
6539 /* HeapReAlloc return NULL, when bufferW was NULL */
6540 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6541 HeapAlloc(GetProcessHeap(), 0, needed);
6543 /* Try again with the large Buffer */
6544 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6546 numentries = pcReturned ? *pcReturned : 0;
6547 needed = 0;
6549 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6550 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6552 if (res) {
6553 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6554 DWORD entrysize = 0;
6555 DWORD index;
6556 LPSTR ptr;
6557 LPMONITOR_INFO_2W mi2w;
6558 LPMONITOR_INFO_2A mi2a;
6560 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6561 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6563 /* First pass: calculate the size for all Entries */
6564 mi2w = (LPMONITOR_INFO_2W) bufferW;
6565 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6566 index = 0;
6567 while (index < numentries) {
6568 index++;
6569 needed += entrysize; /* MONITOR_INFO_?A */
6570 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6572 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6573 NULL, 0, NULL, NULL);
6574 if (Level > 1) {
6575 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6576 NULL, 0, NULL, NULL);
6577 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6578 NULL, 0, NULL, NULL);
6580 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6581 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6582 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6585 /* check for errors and quit on failure */
6586 if (cbBuf < needed) {
6587 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6588 res = FALSE;
6589 goto emA_cleanup;
6591 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6592 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6593 cbBuf -= len ; /* free Bytes in the user-Buffer */
6594 mi2w = (LPMONITOR_INFO_2W) bufferW;
6595 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6596 index = 0;
6597 /* Second Pass: Fill the User Buffer (if we have one) */
6598 while ((index < numentries) && pMonitors) {
6599 index++;
6600 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6601 mi2a->pName = ptr;
6602 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6603 ptr, cbBuf , NULL, NULL);
6604 ptr += len;
6605 cbBuf -= len;
6606 if (Level > 1) {
6607 mi2a->pEnvironment = ptr;
6608 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6609 ptr, cbBuf, NULL, NULL);
6610 ptr += len;
6611 cbBuf -= len;
6613 mi2a->pDLLName = ptr;
6614 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6615 ptr, cbBuf, NULL, NULL);
6616 ptr += len;
6617 cbBuf -= len;
6619 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6620 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6621 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6624 emA_cleanup:
6625 if (pcbNeeded) *pcbNeeded = needed;
6626 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6628 HeapFree(GetProcessHeap(), 0, nameW);
6629 HeapFree(GetProcessHeap(), 0, bufferW);
6631 TRACE("returning %d with %d (%d byte for %d entries)\n",
6632 (res), GetLastError(), needed, numentries);
6634 return (res);
6638 /*****************************************************************************
6639 * EnumMonitorsW [WINSPOOL.@]
6641 * Enumerate available Port-Monitors
6643 * PARAMS
6644 * pName [I] Servername or NULL (local Computer)
6645 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6646 * pMonitors [O] PTR to Buffer that receives the Result
6647 * cbBuf [I] Size of Buffer at pMonitors
6648 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6649 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6651 * RETURNS
6652 * Success: TRUE
6653 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6655 * NOTES
6656 * Windows reads the Registry once and cache the Results.
6658 *| Language-Monitors are also installed in the same Registry-Location but
6659 *| they are filtered in Windows (not returned by EnumMonitors).
6660 *| We do no filtering to simplify our Code.
6663 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6664 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6666 DWORD needed = 0;
6667 DWORD numentries = 0;
6668 BOOL res = FALSE;
6670 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6671 cbBuf, pcbNeeded, pcReturned);
6673 if (pName && (lstrlenW(pName))) {
6674 FIXME("for Server %s not implemented\n", debugstr_w(pName));
6675 SetLastError(ERROR_ACCESS_DENIED);
6676 goto emW_cleanup;
6679 /* Level is not checked in win9x */
6680 if (!Level || (Level > 2)) {
6681 WARN("level (%d) is ignored in win9x\n", Level);
6682 SetLastError(ERROR_INVALID_LEVEL);
6683 goto emW_cleanup;
6685 if (!pcbNeeded) {
6686 SetLastError(RPC_X_NULL_REF_POINTER);
6687 goto emW_cleanup;
6690 /* Scan all Monitor-Keys */
6691 numentries = 0;
6692 needed = get_local_monitors(Level, NULL, 0, &numentries);
6694 /* we calculated the needed buffersize. now do the error-checks */
6695 if (cbBuf < needed) {
6696 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6697 goto emW_cleanup;
6699 else if (!pMonitors || !pcReturned) {
6700 SetLastError(RPC_X_NULL_REF_POINTER);
6701 goto emW_cleanup;
6704 /* fill the Buffer with the Monitor-Keys */
6705 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
6706 res = TRUE;
6708 emW_cleanup:
6709 if (pcbNeeded) *pcbNeeded = needed;
6710 if (pcReturned) *pcReturned = numentries;
6712 TRACE("returning %d with %d (%d byte for %d entries)\n",
6713 res, GetLastError(), needed, numentries);
6715 return (res);
6718 /******************************************************************************
6719 * XcvDataW (WINSPOOL.@)
6721 * Execute commands in the Printmonitor DLL
6723 * PARAMS
6724 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6725 * pszDataName [i] Name of the command to execute
6726 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6727 * cbInputData [i] Size in Bytes of Buffer at pInputData
6728 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6729 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6730 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6731 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6733 * RETURNS
6734 * Success: TRUE
6735 * Failure: FALSE
6737 * NOTES
6738 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6739 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6741 * Minimal List of commands, that a Printmonitor DLL should support:
6743 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6744 *| "AddPort" : Add a Port
6745 *| "DeletePort": Delete a Port
6747 * Many Printmonitors support additional commands. Examples for localspl.dll:
6748 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6749 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6752 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6753 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6754 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6756 opened_printer_t *printer;
6758 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6759 pInputData, cbInputData, pOutputData,
6760 cbOutputData, pcbOutputNeeded, pdwStatus);
6762 printer = get_opened_printer(hXcv);
6763 if (!printer || (!printer->hXcv)) {
6764 SetLastError(ERROR_INVALID_HANDLE);
6765 return FALSE;
6768 if (!pcbOutputNeeded) {
6769 SetLastError(ERROR_INVALID_PARAMETER);
6770 return FALSE;
6773 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6774 SetLastError(RPC_X_NULL_REF_POINTER);
6775 return FALSE;
6778 *pcbOutputNeeded = 0;
6780 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
6781 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
6783 return TRUE;
6786 /*****************************************************************************
6787 * EnumPrinterDataA [WINSPOOL.@]
6790 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6791 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6792 DWORD cbData, LPDWORD pcbData )
6794 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6795 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6796 return ERROR_NO_MORE_ITEMS;
6799 /*****************************************************************************
6800 * EnumPrinterDataW [WINSPOOL.@]
6803 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6804 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6805 DWORD cbData, LPDWORD pcbData )
6807 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6808 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6809 return ERROR_NO_MORE_ITEMS;
6812 /*****************************************************************************
6813 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6816 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6817 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6818 LPDWORD pcbNeeded, LPDWORD pcReturned)
6820 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6821 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6822 pcbNeeded, pcReturned);
6823 return FALSE;
6826 /*****************************************************************************
6827 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6830 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6831 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6832 LPDWORD pcbNeeded, LPDWORD pcReturned)
6834 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6835 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6836 pcbNeeded, pcReturned);
6837 return FALSE;
6840 /*****************************************************************************
6841 * EnumPrintProcessorsA [WINSPOOL.@]
6844 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6845 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
6847 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
6848 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
6849 return FALSE;
6852 /*****************************************************************************
6853 * EnumPrintProcessorsW [WINSPOOL.@]
6856 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
6857 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
6859 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6860 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
6861 cbBuf, pcbNeeded, pcbReturned);
6862 return FALSE;
6865 /*****************************************************************************
6866 * ExtDeviceMode [WINSPOOL.@]
6869 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
6870 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
6871 DWORD fMode)
6873 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
6874 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
6875 debugstr_a(pProfile), fMode);
6876 return -1;
6879 /*****************************************************************************
6880 * FindClosePrinterChangeNotification [WINSPOOL.@]
6883 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
6885 FIXME("Stub: %p\n", hChange);
6886 return TRUE;
6889 /*****************************************************************************
6890 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6893 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
6894 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
6896 FIXME("Stub: %p %x %x %p\n",
6897 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
6898 return INVALID_HANDLE_VALUE;
6901 /*****************************************************************************
6902 * FindNextPrinterChangeNotification [WINSPOOL.@]
6905 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
6906 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
6908 FIXME("Stub: %p %p %p %p\n",
6909 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
6910 return FALSE;
6913 /*****************************************************************************
6914 * FreePrinterNotifyInfo [WINSPOOL.@]
6917 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
6919 FIXME("Stub: %p\n", pPrinterNotifyInfo);
6920 return TRUE;
6923 /*****************************************************************************
6924 * string_to_buf
6926 * Copies a unicode string into a buffer. The buffer will either contain unicode or
6927 * ansi depending on the unicode parameter.
6929 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
6931 if(!str)
6933 *size = 0;
6934 return TRUE;
6937 if(unicode)
6939 *size = (strlenW(str) + 1) * sizeof(WCHAR);
6940 if(*size <= cb)
6942 memcpy(ptr, str, *size);
6943 return TRUE;
6945 return FALSE;
6947 else
6949 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
6950 if(*size <= cb)
6952 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
6953 return TRUE;
6955 return FALSE;
6959 /*****************************************************************************
6960 * get_job_info_1
6962 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
6963 LPDWORD pcbNeeded, BOOL unicode)
6965 DWORD size, left = cbBuf;
6966 BOOL space = (cbBuf > 0);
6967 LPBYTE ptr = buf;
6969 *pcbNeeded = 0;
6971 if(space)
6973 ji1->JobId = job->job_id;
6976 string_to_buf(job->document_title, ptr, left, &size, unicode);
6977 if(space && size <= left)
6979 ji1->pDocument = (LPWSTR)ptr;
6980 ptr += size;
6981 left -= size;
6983 else
6984 space = FALSE;
6985 *pcbNeeded += size;
6987 return space;
6990 /*****************************************************************************
6991 * get_job_info_2
6993 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
6994 LPDWORD pcbNeeded, BOOL unicode)
6996 DWORD size, left = cbBuf;
6997 BOOL space = (cbBuf > 0);
6998 LPBYTE ptr = buf;
7000 *pcbNeeded = 0;
7002 if(space)
7004 ji2->JobId = job->job_id;
7007 string_to_buf(job->document_title, ptr, left, &size, unicode);
7008 if(space && size <= left)
7010 ji2->pDocument = (LPWSTR)ptr;
7011 ptr += size;
7012 left -= size;
7014 else
7015 space = FALSE;
7016 *pcbNeeded += size;
7018 return space;
7021 /*****************************************************************************
7022 * get_job_info
7024 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7025 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7027 BOOL ret = FALSE;
7028 DWORD needed = 0, size;
7029 job_t *job;
7030 LPBYTE ptr = pJob;
7032 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7034 EnterCriticalSection(&printer_handles_cs);
7035 job = get_job(hPrinter, JobId);
7036 if(!job)
7037 goto end;
7039 switch(Level)
7041 case 1:
7042 size = sizeof(JOB_INFO_1W);
7043 if(cbBuf >= size)
7045 cbBuf -= size;
7046 ptr += size;
7047 memset(pJob, 0, size);
7049 else
7050 cbBuf = 0;
7051 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7052 needed += size;
7053 break;
7055 case 2:
7056 size = sizeof(JOB_INFO_2W);
7057 if(cbBuf >= size)
7059 cbBuf -= size;
7060 ptr += size;
7061 memset(pJob, 0, size);
7063 else
7064 cbBuf = 0;
7065 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7066 needed += size;
7067 break;
7069 case 3:
7070 size = sizeof(JOB_INFO_3);
7071 if(cbBuf >= size)
7073 cbBuf -= size;
7074 memset(pJob, 0, size);
7075 ret = TRUE;
7077 else
7078 cbBuf = 0;
7079 needed = size;
7080 break;
7082 default:
7083 SetLastError(ERROR_INVALID_LEVEL);
7084 goto end;
7086 if(pcbNeeded)
7087 *pcbNeeded = needed;
7088 end:
7089 LeaveCriticalSection(&printer_handles_cs);
7090 return ret;
7093 /*****************************************************************************
7094 * GetJobA [WINSPOOL.@]
7097 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7098 DWORD cbBuf, LPDWORD pcbNeeded)
7100 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7103 /*****************************************************************************
7104 * GetJobW [WINSPOOL.@]
7107 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7108 DWORD cbBuf, LPDWORD pcbNeeded)
7110 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7113 /*****************************************************************************
7114 * schedule_lpr
7116 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7118 char *unixname, *queue, *cmd;
7119 char fmt[] = "lpr -P%s %s";
7120 DWORD len;
7122 if(!(unixname = wine_get_unix_file_name(filename)))
7123 return FALSE;
7125 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7126 queue = HeapAlloc(GetProcessHeap(), 0, len);
7127 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7129 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7130 sprintf(cmd, fmt, queue, unixname);
7132 TRACE("printing with: %s\n", cmd);
7133 system(cmd);
7135 HeapFree(GetProcessHeap(), 0, cmd);
7136 HeapFree(GetProcessHeap(), 0, queue);
7137 HeapFree(GetProcessHeap(), 0, unixname);
7138 return TRUE;
7141 /*****************************************************************************
7142 * schedule_cups
7144 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7146 #ifdef SONAME_LIBCUPS
7147 if(pcupsPrintFile)
7149 char *unixname, *queue, *doc_titleA;
7150 DWORD len;
7151 BOOL ret;
7153 if(!(unixname = wine_get_unix_file_name(filename)))
7154 return FALSE;
7156 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7157 queue = HeapAlloc(GetProcessHeap(), 0, len);
7158 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7160 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
7161 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
7162 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
7164 TRACE("printing via cups\n");
7165 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
7166 HeapFree(GetProcessHeap(), 0, doc_titleA);
7167 HeapFree(GetProcessHeap(), 0, queue);
7168 HeapFree(GetProcessHeap(), 0, unixname);
7169 return ret;
7171 else
7172 #endif
7174 return schedule_lpr(printer_name, filename);
7178 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7180 LPWSTR filename;
7182 switch(msg)
7184 case WM_INITDIALOG:
7185 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7186 return TRUE;
7188 case WM_COMMAND:
7189 if(HIWORD(wparam) == BN_CLICKED)
7191 if(LOWORD(wparam) == IDOK)
7193 HANDLE hf;
7194 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7195 LPWSTR *output;
7197 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7198 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7200 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7202 WCHAR caption[200], message[200];
7203 int mb_ret;
7205 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7206 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7207 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7208 if(mb_ret == IDCANCEL)
7210 HeapFree(GetProcessHeap(), 0, filename);
7211 return TRUE;
7214 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7215 if(hf == INVALID_HANDLE_VALUE)
7217 WCHAR caption[200], message[200];
7219 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7220 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7221 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7222 HeapFree(GetProcessHeap(), 0, filename);
7223 return TRUE;
7225 CloseHandle(hf);
7226 DeleteFileW(filename);
7227 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7228 *output = filename;
7229 EndDialog(hwnd, IDOK);
7230 return TRUE;
7232 if(LOWORD(wparam) == IDCANCEL)
7234 EndDialog(hwnd, IDCANCEL);
7235 return TRUE;
7238 return FALSE;
7240 return FALSE;
7243 /*****************************************************************************
7244 * get_filename
7246 static BOOL get_filename(LPWSTR *filename)
7248 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7249 file_dlg_proc, (LPARAM)filename) == IDOK;
7252 /*****************************************************************************
7253 * schedule_file
7255 static BOOL schedule_file(LPCWSTR filename)
7257 LPWSTR output = NULL;
7259 if(get_filename(&output))
7261 TRACE("copy to %s\n", debugstr_w(output));
7262 CopyFileW(filename, output, FALSE);
7263 HeapFree(GetProcessHeap(), 0, output);
7264 return TRUE;
7266 return FALSE;
7269 /*****************************************************************************
7270 * schedule_pipe
7272 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7274 #ifdef HAVE_FORK
7275 char *unixname, *cmdA;
7276 DWORD len;
7277 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7278 BOOL ret = FALSE;
7279 char buf[1024];
7281 if(!(unixname = wine_get_unix_file_name(filename)))
7282 return FALSE;
7284 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
7285 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7286 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
7288 TRACE("printing with: %s\n", cmdA);
7290 if((file_fd = open(unixname, O_RDONLY)) == -1)
7291 goto end;
7293 if (pipe(fds))
7295 ERR("pipe() failed!\n");
7296 goto end;
7299 if (fork() == 0)
7301 close(0);
7302 dup2(fds[0], 0);
7303 close(fds[1]);
7305 /* reset signals that we previously set to SIG_IGN */
7306 signal(SIGPIPE, SIG_DFL);
7307 signal(SIGCHLD, SIG_DFL);
7309 execl("/bin/sh", "/bin/sh", "-c", cmdA, (char*)0);
7310 _exit(1);
7313 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7314 write(fds[1], buf, no_read);
7316 ret = TRUE;
7318 end:
7319 if(file_fd != -1) close(file_fd);
7320 if(fds[0] != -1) close(fds[0]);
7321 if(fds[1] != -1) close(fds[1]);
7323 HeapFree(GetProcessHeap(), 0, cmdA);
7324 HeapFree(GetProcessHeap(), 0, unixname);
7325 return ret;
7326 #else
7327 return FALSE;
7328 #endif
7331 /*****************************************************************************
7332 * schedule_unixfile
7334 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7336 int in_fd, out_fd, no_read;
7337 char buf[1024];
7338 BOOL ret = FALSE;
7339 char *unixname, *outputA;
7340 DWORD len;
7342 if(!(unixname = wine_get_unix_file_name(filename)))
7343 return FALSE;
7345 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
7346 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7347 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
7349 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7350 in_fd = open(unixname, O_RDONLY);
7351 if(out_fd == -1 || in_fd == -1)
7352 goto end;
7354 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7355 write(out_fd, buf, no_read);
7357 ret = TRUE;
7358 end:
7359 if(in_fd != -1) close(in_fd);
7360 if(out_fd != -1) close(out_fd);
7361 HeapFree(GetProcessHeap(), 0, outputA);
7362 HeapFree(GetProcessHeap(), 0, unixname);
7363 return ret;
7366 /*****************************************************************************
7367 * ScheduleJob [WINSPOOL.@]
7370 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7372 opened_printer_t *printer;
7373 BOOL ret = FALSE;
7374 struct list *cursor, *cursor2;
7376 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7377 EnterCriticalSection(&printer_handles_cs);
7378 printer = get_opened_printer(hPrinter);
7379 if(!printer)
7380 goto end;
7382 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7384 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7385 HANDLE hf;
7387 if(job->job_id != dwJobID) continue;
7389 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7390 if(hf != INVALID_HANDLE_VALUE)
7392 PRINTER_INFO_5W *pi5;
7393 DWORD needed;
7394 HKEY hkey;
7395 WCHAR output[1024];
7396 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7397 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7399 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7400 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7401 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7402 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7403 debugstr_w(pi5->pPortName));
7405 output[0] = 0;
7407 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7408 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7410 DWORD type, count = sizeof(output);
7411 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7412 RegCloseKey(hkey);
7414 if(output[0] == '|')
7416 schedule_pipe(output + 1, job->filename);
7418 else if(output[0])
7420 schedule_unixfile(output, job->filename);
7422 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7424 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7426 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7428 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7430 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7432 schedule_file(job->filename);
7434 else
7436 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7438 HeapFree(GetProcessHeap(), 0, pi5);
7439 CloseHandle(hf);
7440 DeleteFileW(job->filename);
7442 list_remove(cursor);
7443 HeapFree(GetProcessHeap(), 0, job->document_title);
7444 HeapFree(GetProcessHeap(), 0, job->filename);
7445 HeapFree(GetProcessHeap(), 0, job);
7446 ret = TRUE;
7447 break;
7449 end:
7450 LeaveCriticalSection(&printer_handles_cs);
7451 return ret;
7454 /*****************************************************************************
7455 * StartDocDlgA [WINSPOOL.@]
7457 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7459 UNICODE_STRING usBuffer;
7460 DOCINFOW docW;
7461 LPWSTR retW;
7462 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7463 LPSTR ret = NULL;
7465 docW.cbSize = sizeof(docW);
7466 if (doc->lpszDocName)
7468 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7469 if (!(docW.lpszDocName = docnameW)) return NULL;
7471 if (doc->lpszOutput)
7473 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7474 if (!(docW.lpszOutput = outputW)) return NULL;
7476 if (doc->lpszDatatype)
7478 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7479 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7481 docW.fwType = doc->fwType;
7483 retW = StartDocDlgW(hPrinter, &docW);
7485 if(retW)
7487 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7488 ret = HeapAlloc(GetProcessHeap(), 0, len);
7489 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7490 HeapFree(GetProcessHeap(), 0, retW);
7493 HeapFree(GetProcessHeap(), 0, datatypeW);
7494 HeapFree(GetProcessHeap(), 0, outputW);
7495 HeapFree(GetProcessHeap(), 0, docnameW);
7497 return ret;
7500 /*****************************************************************************
7501 * StartDocDlgW [WINSPOOL.@]
7503 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7504 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7505 * port is "FILE:". Also returns the full path if passed a relative path.
7507 * The caller should free the returned string from the process heap.
7509 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7511 LPWSTR ret = NULL;
7512 DWORD len, attr;
7514 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7516 PRINTER_INFO_5W *pi5;
7517 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7518 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7519 return NULL;
7520 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7521 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7522 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7524 HeapFree(GetProcessHeap(), 0, pi5);
7525 return NULL;
7527 HeapFree(GetProcessHeap(), 0, pi5);
7530 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7532 LPWSTR name;
7534 if (get_filename(&name))
7536 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7538 HeapFree(GetProcessHeap(), 0, name);
7539 return NULL;
7541 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7542 GetFullPathNameW(name, len, ret, NULL);
7543 HeapFree(GetProcessHeap(), 0, name);
7545 return ret;
7548 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7549 return NULL;
7551 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7552 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7554 attr = GetFileAttributesW(ret);
7555 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7557 HeapFree(GetProcessHeap(), 0, ret);
7558 ret = NULL;
7560 return ret;