mshtml.idl: Added some missing attributes.
[wine.git] / dlls / winspool.drv / info.c
blob2d892a345902e21029fc2320f0b5d9c01b84e51a
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 Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
196 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
197 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
198 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
200 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
201 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
203 static const WCHAR backslashW[] = {'\\',0};
204 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
205 'i','o','n',' ','F','i','l','e',0};
206 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
207 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
208 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
209 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
210 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
211 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
212 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
213 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
214 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
215 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
216 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
217 static const WCHAR MonitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
218 static const WCHAR NameW[] = {'N','a','m','e',0};
219 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
220 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
221 static const WCHAR PortW[] = {'P','o','r','t',0};
222 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
223 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
224 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
225 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
226 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
227 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
228 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
229 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
230 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
231 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
232 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
233 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
234 static const WCHAR emptyStringW[] = {0};
235 static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
236 static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
238 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
240 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
241 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
242 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
244 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
245 'D','o','c','u','m','e','n','t',0};
247 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
248 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
249 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
250 0, sizeof(DRIVER_INFO_8W)};
252 /******************************************************************
253 * validate the user-supplied printing-environment [internal]
255 * PARAMS
256 * env [I] PTR to Environment-String or NULL
258 * RETURNS
259 * Failure: NULL
260 * Success: PTR to printenv_t
262 * NOTES
263 * An empty string is handled the same way as NULL.
264 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
268 static const printenv_t * validate_envW(LPCWSTR env)
270 static const printenv_t env_x86 = {envname_x86W, subdir_x86W,
271 3, Version3_RegPathW, Version3_SubdirW};
272 static const printenv_t env_win40 = {envname_win40W, subdir_win40W,
273 0, Version0_RegPathW, Version0_SubdirW};
275 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
277 const printenv_t *result = NULL;
278 unsigned int i;
280 TRACE("testing %s\n", debugstr_w(env));
281 if (env && env[0])
283 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
285 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
287 result = all_printenv[i];
288 break;
292 if (result == NULL) {
293 FIXME("unsupported Environment: %s\n", debugstr_w(env));
294 SetLastError(ERROR_INVALID_ENVIRONMENT);
296 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
298 else
300 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
302 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
304 return result;
308 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
309 if passed a NULL string. This returns NULLs to the result.
311 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
313 if ( (src) )
315 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
316 return usBufferPtr->Buffer;
318 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
319 return NULL;
322 static LPWSTR strdupW(LPCWSTR p)
324 LPWSTR ret;
325 DWORD len;
327 if(!p) return NULL;
328 len = (strlenW(p) + 1) * sizeof(WCHAR);
329 ret = HeapAlloc(GetProcessHeap(), 0, len);
330 memcpy(ret, p, len);
331 return ret;
334 static LPSTR strdupWtoA( LPCWSTR str )
336 LPSTR ret;
337 INT len;
339 if (!str) return NULL;
340 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
341 ret = HeapAlloc( GetProcessHeap(), 0, len );
342 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
343 return ret;
346 /* Returns the number of bytes in an ansi \0\0 terminated string (multi_sz).
347 The result includes all \0s (specifically the last two). */
348 static int multi_sz_lenA(const char *str)
350 const char *ptr = str;
351 if(!str) return 0;
354 ptr += lstrlenA(ptr) + 1;
355 } while(*ptr);
357 return ptr - str + 1;
360 static void
361 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
362 char qbuf[200];
364 /* If forcing, or no profile string entry for device yet, set the entry
366 * The always change entry if not WINEPS yet is discussable.
368 if (force ||
369 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
370 !strcmp(qbuf,"*") ||
371 !strstr(qbuf,"WINEPS.DRV")
373 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
374 HKEY hkey;
376 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
377 WriteProfileStringA("windows","device",buf);
378 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
379 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
380 RegCloseKey(hkey);
382 HeapFree(GetProcessHeap(),0,buf);
386 static BOOL add_printer_driver(const char *name)
388 DRIVER_INFO_3A di3a;
390 static char driver_path[] = "wineps16",
391 data_file[] = "<datafile?>",
392 config_file[] = "wineps16",
393 help_file[] = "<helpfile?>",
394 dep_file[] = "<dependent files?>\0",
395 monitor_name[] = "<monitor name?>",
396 default_data_type[] = "RAW";
398 di3a.cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
399 di3a.pName = (char *)name;
400 di3a.pEnvironment = NULL; /* NULL means auto */
401 di3a.pDriverPath = driver_path;
402 di3a.pDataFile = data_file;
403 di3a.pConfigFile = config_file;
404 di3a.pHelpFile = help_file;
405 di3a.pDependentFiles = dep_file;
406 di3a.pMonitorName = monitor_name;
407 di3a.pDefaultDataType = default_data_type;
409 if (!AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a))
411 ERR("Failed adding driver (%d)\n", GetLastError());
412 return FALSE;
414 return TRUE;
417 #ifdef SONAME_LIBCUPS
418 static typeof(cupsGetDests) *pcupsGetDests;
419 static typeof(cupsGetPPD) *pcupsGetPPD;
420 static typeof(cupsPrintFile) *pcupsPrintFile;
421 static void *cupshandle;
423 static BOOL CUPS_LoadPrinters(void)
425 int i, nrofdests;
426 BOOL hadprinter = FALSE, haddefault = FALSE;
427 cups_dest_t *dests;
428 PRINTER_INFO_2A pinfo2a;
429 char *port,*devline;
430 HKEY hkeyPrinter, hkeyPrinters, hkey;
432 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
433 if (!cupshandle)
434 return FALSE;
435 TRACE("loaded %s\n", SONAME_LIBCUPS);
437 #define DYNCUPS(x) \
438 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
439 if (!p##x) return FALSE;
441 DYNCUPS(cupsGetPPD);
442 DYNCUPS(cupsGetDests);
443 DYNCUPS(cupsPrintFile);
444 #undef DYNCUPS
446 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
447 ERROR_SUCCESS) {
448 ERR("Can't create Printers key\n");
449 return FALSE;
452 nrofdests = pcupsGetDests(&dests);
453 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
454 for (i=0;i<nrofdests;i++) {
455 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
456 sprintf(port,"LPR:%s",dests[i].name);
457 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
458 sprintf(devline,"WINEPS.DRV,%s",port);
459 WriteProfileStringA("devices",dests[i].name,devline);
460 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
461 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
462 RegCloseKey(hkey);
464 HeapFree(GetProcessHeap(),0,devline);
466 TRACE("Printer %d: %s\n", i, dests[i].name);
467 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
468 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
469 and continue */
470 TRACE("Printer already exists\n");
471 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
472 RegCloseKey(hkeyPrinter);
473 } else {
474 static CHAR data_type[] = "RAW",
475 print_proc[] = "WinPrint",
476 comment[] = "WINEPS Printer using CUPS",
477 location[] = "<physical location of printer>",
478 params[] = "<parameters?>",
479 share_name[] = "<share name?>",
480 sep_file[] = "<sep file?>";
482 add_printer_driver(dests[i].name);
484 memset(&pinfo2a,0,sizeof(pinfo2a));
485 pinfo2a.pPrinterName = dests[i].name;
486 pinfo2a.pDatatype = data_type;
487 pinfo2a.pPrintProcessor = print_proc;
488 pinfo2a.pDriverName = dests[i].name;
489 pinfo2a.pComment = comment;
490 pinfo2a.pLocation = location;
491 pinfo2a.pPortName = port;
492 pinfo2a.pParameters = params;
493 pinfo2a.pShareName = share_name;
494 pinfo2a.pSepFile = sep_file;
496 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
497 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
498 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
501 HeapFree(GetProcessHeap(),0,port);
503 hadprinter = TRUE;
504 if (dests[i].is_default) {
505 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
506 haddefault = TRUE;
509 if (hadprinter & !haddefault)
510 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
511 RegCloseKey(hkeyPrinters);
512 return hadprinter;
514 #endif
516 static BOOL
517 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
518 PRINTER_INFO_2A pinfo2a;
519 char *e,*s,*name,*prettyname,*devname;
520 BOOL ret = FALSE, set_default = FALSE;
521 char *port,*devline,*env_default;
522 HKEY hkeyPrinter, hkeyPrinters, hkey;
524 while (isspace(*pent)) pent++;
525 s = strchr(pent,':');
526 if(s) *s='\0';
527 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
528 strcpy(name,pent);
529 if(s) {
530 *s=':';
531 pent = s;
532 } else
533 pent = "";
535 TRACE("name=%s entry=%s\n",name, pent);
537 if(ispunct(*name)) { /* a tc entry, not a real printer */
538 TRACE("skipping tc entry\n");
539 goto end;
542 if(strstr(pent,":server")) { /* server only version so skip */
543 TRACE("skipping server entry\n");
544 goto end;
547 /* Determine whether this is a postscript printer. */
549 ret = TRUE;
550 env_default = getenv("PRINTER");
551 prettyname = name;
552 /* Get longest name, usually the one at the right for later display. */
553 while((s=strchr(prettyname,'|'))) {
554 *s = '\0';
555 e = s;
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;
559 for(prettyname = s+1; isspace(*prettyname); prettyname++)
562 e = prettyname + strlen(prettyname);
563 while(isspace(*--e)) *e = '\0';
564 TRACE("\t%s\n", debugstr_a(prettyname));
565 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
567 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
568 * if it is too long, we use it as comment below. */
569 devname = prettyname;
570 if (strlen(devname)>=CCHDEVICENAME-1)
571 devname = name;
572 if (strlen(devname)>=CCHDEVICENAME-1) {
573 ret = FALSE;
574 goto end;
577 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
578 sprintf(port,"LPR:%s",name);
580 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
581 sprintf(devline,"WINEPS.DRV,%s",port);
582 WriteProfileStringA("devices",devname,devline);
583 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
584 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
585 RegCloseKey(hkey);
587 HeapFree(GetProcessHeap(),0,devline);
589 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
590 ERROR_SUCCESS) {
591 ERR("Can't create Printers key\n");
592 ret = FALSE;
593 goto end;
595 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
596 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
597 and continue */
598 TRACE("Printer already exists\n");
599 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
600 RegCloseKey(hkeyPrinter);
601 } else {
602 static CHAR data_type[] = "RAW",
603 print_proc[] = "WinPrint",
604 comment[] = "WINEPS Printer using LPR",
605 params[] = "<parameters?>",
606 share_name[] = "<share name?>",
607 sep_file[] = "<sep file?>";
609 add_printer_driver(devname);
611 memset(&pinfo2a,0,sizeof(pinfo2a));
612 pinfo2a.pPrinterName = devname;
613 pinfo2a.pDatatype = data_type;
614 pinfo2a.pPrintProcessor = print_proc;
615 pinfo2a.pDriverName = devname;
616 pinfo2a.pComment = comment;
617 pinfo2a.pLocation = prettyname;
618 pinfo2a.pPortName = port;
619 pinfo2a.pParameters = params;
620 pinfo2a.pShareName = share_name;
621 pinfo2a.pSepFile = sep_file;
623 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
624 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
625 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
628 RegCloseKey(hkeyPrinters);
630 if (isfirst || set_default)
631 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
633 HeapFree(GetProcessHeap(), 0, port);
634 end:
635 HeapFree(GetProcessHeap(), 0, name);
636 return ret;
639 static BOOL
640 PRINTCAP_LoadPrinters(void) {
641 BOOL hadprinter = FALSE;
642 char buf[200];
643 FILE *f;
644 char *pent = NULL;
645 BOOL had_bash = FALSE;
647 f = fopen("/etc/printcap","r");
648 if (!f)
649 return FALSE;
651 while(fgets(buf,sizeof(buf),f)) {
652 char *start, *end;
654 end=strchr(buf,'\n');
655 if (end) *end='\0';
657 start = buf;
658 while(isspace(*start)) start++;
659 if(*start == '#' || *start == '\0')
660 continue;
662 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
663 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
664 HeapFree(GetProcessHeap(),0,pent);
665 pent = NULL;
668 if (end && *--end == '\\') {
669 *end = '\0';
670 had_bash = TRUE;
671 } else
672 had_bash = FALSE;
674 if (pent) {
675 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
676 strcat(pent,start);
677 } else {
678 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
679 strcpy(pent,start);
683 if(pent) {
684 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
685 HeapFree(GetProcessHeap(),0,pent);
687 fclose(f);
688 return hadprinter;
691 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
693 if (value)
694 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
695 (lstrlenW(value) + 1) * sizeof(WCHAR));
696 else
697 return ERROR_FILE_NOT_FOUND;
700 /*****************************************************************************
701 * enumerate the local monitors (INTERNAL)
703 * returns the needed size (in bytes) for pMonitors
704 * and *lpreturned is set to number of entries returned in pMonitors
707 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
709 HKEY hroot = NULL;
710 HKEY hentry = NULL;
711 LPWSTR ptr;
712 LPMONITOR_INFO_2W mi;
713 WCHAR buffer[MAX_PATH];
714 WCHAR dllname[MAX_PATH];
715 DWORD dllsize;
716 DWORD len;
717 DWORD index = 0;
718 DWORD needed = 0;
719 DWORD numentries;
720 DWORD entrysize;
722 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
724 numentries = *lpreturned; /* this is 0, when we scan the registry */
725 len = entrysize * numentries;
726 ptr = (LPWSTR) &pMonitors[len];
728 numentries = 0;
729 len = sizeof(buffer);
730 buffer[0] = '\0';
732 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
733 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
734 /* Scan all Monitor-Registry-Keys */
735 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
736 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
737 dllsize = sizeof(dllname);
738 dllname[0] = '\0';
740 /* The Monitor must have a Driver-DLL */
741 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
742 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
743 /* We found a valid DLL for this Monitor. */
744 TRACE("using Driver: %s\n", debugstr_w(dllname));
746 RegCloseKey(hentry);
749 /* Windows returns only Port-Monitors here, but to simplify our code,
750 we do no filtering for Language-Monitors */
751 if (dllname[0]) {
752 numentries++;
753 needed += entrysize;
754 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
755 if (level > 1) {
756 /* we install and return only monitors for "Windows NT x86" */
757 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
758 needed += dllsize;
761 /* required size is calculated. Now fill the user-buffer */
762 if (pMonitors && (cbBuf >= needed)){
763 mi = (LPMONITOR_INFO_2W) pMonitors;
764 pMonitors += entrysize;
766 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
767 mi->pName = ptr;
768 lstrcpyW(ptr, buffer); /* Name of the Monitor */
769 ptr += (len+1); /* len is lstrlenW(monitorname) */
770 if (level > 1) {
771 mi->pEnvironment = ptr;
772 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
773 ptr += (lstrlenW(envname_x86W)+1);
775 mi->pDLLName = ptr;
776 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
777 ptr += (dllsize / sizeof(WCHAR));
781 index++;
782 len = sizeof(buffer);
783 buffer[0] = '\0';
785 RegCloseKey(hroot);
787 *lpreturned = numentries;
788 TRACE("need %d byte for %d entries\n", needed, numentries);
789 return needed;
792 /******************************************************************
793 * monitor_unload [internal]
795 * release a printmonitor and unload it from memory, when needed
798 static void monitor_unload(monitor_t * pm)
800 if (pm == NULL) return;
801 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
803 EnterCriticalSection(&monitor_handles_cs);
805 if (pm->refcount) pm->refcount--;
807 if (pm->refcount == 0) {
808 list_remove(&pm->entry);
809 FreeLibrary(pm->hdll);
810 HeapFree(GetProcessHeap(), 0, pm->name);
811 HeapFree(GetProcessHeap(), 0, pm->dllname);
812 HeapFree(GetProcessHeap(), 0, pm);
814 LeaveCriticalSection(&monitor_handles_cs);
817 /******************************************************************
818 * monitor_unloadall [internal]
820 * release all printmonitors and unload them from memory, when needed
823 static void monitor_unloadall(void)
825 monitor_t * pm;
826 monitor_t * next;
828 EnterCriticalSection(&monitor_handles_cs);
829 /* iterate through the list, with safety against removal */
830 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
832 monitor_unload(pm);
834 LeaveCriticalSection(&monitor_handles_cs);
837 /******************************************************************
838 * monitor_load [internal]
840 * load a printmonitor, get the dllname from the registry, when needed
841 * initialize the monitor and dump found function-pointers
843 * On failure, SetLastError() is called and NULL is returned
846 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
848 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
849 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
850 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
851 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
852 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
854 monitor_t * pm = NULL;
855 monitor_t * cursor;
856 LPWSTR regroot = NULL;
857 LPWSTR driver = dllname;
859 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
860 /* Is the Monitor already loaded? */
861 EnterCriticalSection(&monitor_handles_cs);
863 if (name) {
864 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
866 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
867 pm = cursor;
868 break;
873 if (pm == NULL) {
874 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
875 if (pm == NULL) goto cleanup;
876 list_add_tail(&monitor_handles, &pm->entry);
878 pm->refcount++;
880 if (pm->name == NULL) {
881 /* Load the monitor */
882 LPMONITOREX pmonitorEx;
883 DWORD len;
885 if (name) {
886 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
887 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
890 if (regroot) {
891 lstrcpyW(regroot, MonitorsW);
892 lstrcatW(regroot, name);
893 /* Get the Driver from the Registry */
894 if (driver == NULL) {
895 HKEY hroot;
896 DWORD namesize;
897 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
898 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
899 &namesize) == ERROR_SUCCESS) {
900 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
901 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
903 RegCloseKey(hroot);
908 pm->name = strdupW(name);
909 pm->dllname = strdupW(driver);
911 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
912 monitor_unload(pm);
913 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
914 pm = NULL;
915 goto cleanup;
918 pm->hdll = LoadLibraryW(driver);
919 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
921 if (pm->hdll == NULL) {
922 monitor_unload(pm);
923 SetLastError(ERROR_MOD_NOT_FOUND);
924 pm = NULL;
925 goto cleanup;
928 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
929 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
930 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
931 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
932 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
935 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
936 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
937 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
938 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
939 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
941 if (pInitializePrintMonitorUI != NULL) {
942 pm->monitorUI = pInitializePrintMonitorUI();
943 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
944 if (pm->monitorUI) {
945 TRACE( "0x%08x: dwMonitorSize (%d)\n",
946 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
951 if (pInitializePrintMonitor && regroot) {
952 pmonitorEx = pInitializePrintMonitor(regroot);
953 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
954 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
956 if (pmonitorEx) {
957 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
958 pm->monitor = &(pmonitorEx->Monitor);
962 if (pm->monitor) {
963 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
967 if (!pm->monitor && regroot) {
968 if (pInitializePrintMonitor2 != NULL) {
969 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
971 if (pInitializeMonitorEx != NULL) {
972 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
974 if (pInitializeMonitor != NULL) {
975 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
978 if (!pm->monitor && !pm->monitorUI) {
979 monitor_unload(pm);
980 SetLastError(ERROR_PROC_NOT_FOUND);
981 pm = NULL;
984 cleanup:
985 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
986 pm->refcount++;
987 pm_localport = pm;
989 LeaveCriticalSection(&monitor_handles_cs);
990 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
991 HeapFree(GetProcessHeap(), 0, regroot);
992 TRACE("=> %p\n", pm);
993 return pm;
996 /******************************************************************
997 * monitor_loadall [internal]
999 * Load all registered monitors
1002 static DWORD monitor_loadall(void)
1004 monitor_t * pm;
1005 DWORD registered = 0;
1006 DWORD loaded = 0;
1007 HKEY hmonitors;
1008 WCHAR buffer[MAX_PATH];
1009 DWORD id = 0;
1011 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hmonitors) == ERROR_SUCCESS) {
1012 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
1013 NULL, NULL, NULL, NULL, NULL);
1015 TRACE("%d monitors registered\n", registered);
1017 EnterCriticalSection(&monitor_handles_cs);
1018 while (id < registered) {
1019 buffer[0] = '\0';
1020 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
1021 pm = monitor_load(buffer, NULL);
1022 if (pm) loaded++;
1023 id++;
1025 LeaveCriticalSection(&monitor_handles_cs);
1026 RegCloseKey(hmonitors);
1028 TRACE("%d monitors loaded\n", loaded);
1029 return loaded;
1032 /******************************************************************
1033 * monitor_loadui [internal]
1035 * load the userinterface-dll for a given portmonitor
1037 * On failure, NULL is returned
1040 static monitor_t * monitor_loadui(monitor_t * pm)
1042 monitor_t * pui = NULL;
1043 LPWSTR buffer[MAX_PATH];
1044 HANDLE hXcv;
1045 DWORD len;
1046 DWORD res;
1048 if (pm == NULL) return NULL;
1049 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
1051 /* Try the Portmonitor first; works for many monitors */
1052 if (pm->monitorUI) {
1053 EnterCriticalSection(&monitor_handles_cs);
1054 pm->refcount++;
1055 LeaveCriticalSection(&monitor_handles_cs);
1056 return pm;
1059 /* query the userinterface-dllname from the Portmonitor */
1060 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
1061 /* building (",XcvMonitor %s",pm->name) not needed yet */
1062 res = pm->monitor->pfnXcvOpenPort(emptyStringW, SERVER_ACCESS_ADMINISTER, &hXcv);
1063 TRACE("got %u with %p\n", res, hXcv);
1064 if (res) {
1065 res = pm->monitor->pfnXcvDataPort(hXcv, MonitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
1066 TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
1067 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
1068 pm->monitor->pfnXcvClosePort(hXcv);
1071 return pui;
1075 /******************************************************************
1076 * monitor_load_by_port [internal]
1078 * load a printmonitor for a given port
1080 * On failure, NULL is returned
1083 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1085 HKEY hroot;
1086 HKEY hport;
1087 LPWSTR buffer;
1088 monitor_t * pm = NULL;
1089 DWORD registered = 0;
1090 DWORD id = 0;
1091 DWORD len;
1093 TRACE("(%s)\n", debugstr_w(portname));
1095 /* Try the Local Monitor first */
1096 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1097 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1098 /* found the portname */
1099 RegCloseKey(hroot);
1100 return monitor_load(LocalPortW, NULL);
1102 RegCloseKey(hroot);
1105 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1106 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1107 if (buffer == NULL) return NULL;
1109 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1110 EnterCriticalSection(&monitor_handles_cs);
1111 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1113 while ((pm == NULL) && (id < registered)) {
1114 buffer[0] = '\0';
1115 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1116 TRACE("testing %s\n", debugstr_w(buffer));
1117 len = lstrlenW(buffer);
1118 lstrcatW(buffer, bs_Ports_bsW);
1119 lstrcatW(buffer, portname);
1120 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1121 RegCloseKey(hport);
1122 buffer[len] = '\0'; /* use only the Monitor-Name */
1123 pm = monitor_load(buffer, NULL);
1125 id++;
1127 LeaveCriticalSection(&monitor_handles_cs);
1128 RegCloseKey(hroot);
1130 HeapFree(GetProcessHeap(), 0, buffer);
1131 return pm;
1134 /******************************************************************
1135 * enumerate the local Ports from all loaded monitors (internal)
1137 * returns the needed size (in bytes) for pPorts
1138 * and *lpreturned is set to number of entries returned in pPorts
1141 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
1143 monitor_t * pm;
1144 LPWSTR ptr;
1145 LPPORT_INFO_2W cache;
1146 LPPORT_INFO_2W out;
1147 LPBYTE pi_buffer = NULL;
1148 DWORD pi_allocated = 0;
1149 DWORD pi_needed;
1150 DWORD pi_index;
1151 DWORD pi_returned;
1152 DWORD res;
1153 DWORD outindex = 0;
1154 DWORD needed;
1155 DWORD numentries;
1156 DWORD entrysize;
1159 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
1160 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
1162 numentries = *lpreturned; /* this is 0, when we scan the registry */
1163 needed = entrysize * numentries;
1164 ptr = (LPWSTR) &pPorts[needed];
1166 numentries = 0;
1167 needed = 0;
1169 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1171 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
1172 pi_needed = 0;
1173 pi_returned = 0;
1174 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1175 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
1176 /* Do not use HeapReAlloc (we do not need the old data in the buffer) */
1177 HeapFree(GetProcessHeap(), 0, pi_buffer);
1178 pi_buffer = HeapAlloc(GetProcessHeap(), 0, pi_needed);
1179 pi_allocated = (pi_buffer) ? pi_needed : 0;
1180 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1182 TRACE( "(%s) got %d with %d (need %d byte for %d entries)\n",
1183 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
1185 numentries += pi_returned;
1186 needed += pi_needed;
1188 /* fill the output-buffer (pPorts), if we have one */
1189 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
1190 pi_index = 0;
1191 while (pi_returned > pi_index) {
1192 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
1193 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
1194 out->pPortName = ptr;
1195 lstrcpyW(ptr, cache->pPortName);
1196 ptr += (lstrlenW(ptr)+1);
1197 if (level > 1) {
1198 out->pMonitorName = ptr;
1199 lstrcpyW(ptr, cache->pMonitorName);
1200 ptr += (lstrlenW(ptr)+1);
1202 out->pDescription = ptr;
1203 lstrcpyW(ptr, cache->pDescription);
1204 ptr += (lstrlenW(ptr)+1);
1205 out->fPortType = cache->fPortType;
1206 out->Reserved = cache->Reserved;
1208 pi_index++;
1209 outindex++;
1214 /* the temporary portinfo-buffer is no longer needed */
1215 HeapFree(GetProcessHeap(), 0, pi_buffer);
1217 *lpreturned = numentries;
1218 TRACE("need %d byte for %d entries\n", needed, numentries);
1219 return needed;
1222 /******************************************************************
1223 * get_servername_from_name (internal)
1225 * for an external server, a copy of the serverpart from the full name is returned
1228 static LPWSTR get_servername_from_name(LPCWSTR name)
1230 LPWSTR server;
1231 LPWSTR ptr;
1232 WCHAR buffer[MAX_PATH];
1233 DWORD len;
1235 if (name == NULL) return NULL;
1236 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1238 server = strdupW(&name[2]); /* skip over both backslash */
1239 if (server == NULL) return NULL;
1241 /* strip '\' and the printername */
1242 ptr = strchrW(server, '\\');
1243 if (ptr) ptr[0] = '\0';
1245 TRACE("found %s\n", debugstr_w(server));
1247 len = sizeof(buffer)/sizeof(buffer[0]);
1248 if (GetComputerNameW(buffer, &len)) {
1249 if (lstrcmpW(buffer, server) == 0) {
1250 /* The requested Servername is our computername */
1251 HeapFree(GetProcessHeap(), 0, server);
1252 return NULL;
1255 return server;
1258 /******************************************************************
1259 * get_basename_from_name (internal)
1261 * skip over the serverpart from the full name
1264 static LPCWSTR get_basename_from_name(LPCWSTR name)
1266 if (name == NULL) return NULL;
1267 if ((name[0] == '\\') && (name[1] == '\\')) {
1268 /* skip over the servername and search for the following '\' */
1269 name = strchrW(&name[2], '\\');
1270 if ((name) && (name[1])) {
1271 /* found a separator ('\') followed by a name:
1272 skip over the separator and return the rest */
1273 name++;
1275 else
1277 /* no basename present (we found only a servername) */
1278 return NULL;
1281 return name;
1284 /******************************************************************
1285 * get_opened_printer_entry
1286 * Get the first place empty in the opened printer table
1288 * ToDo:
1289 * - pDefault is ignored
1291 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1293 UINT_PTR handle = nb_printer_handles, i;
1294 jobqueue_t *queue = NULL;
1295 opened_printer_t *printer = NULL;
1296 LPWSTR servername;
1297 LPCWSTR printername;
1298 HKEY hkeyPrinters;
1299 HKEY hkeyPrinter;
1300 DWORD len;
1302 servername = get_servername_from_name(name);
1303 if (servername) {
1304 FIXME("server %s not supported\n", debugstr_w(servername));
1305 HeapFree(GetProcessHeap(), 0, servername);
1306 SetLastError(ERROR_INVALID_PRINTER_NAME);
1307 return NULL;
1310 printername = get_basename_from_name(name);
1311 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1313 /* an empty printername is invalid */
1314 if (printername && (!printername[0])) {
1315 SetLastError(ERROR_INVALID_PARAMETER);
1316 return NULL;
1319 EnterCriticalSection(&printer_handles_cs);
1321 for (i = 0; i < nb_printer_handles; i++)
1323 if (!printer_handles[i])
1325 if(handle == nb_printer_handles)
1326 handle = i;
1328 else
1330 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1331 queue = printer_handles[i]->queue;
1335 if (handle >= nb_printer_handles)
1337 opened_printer_t **new_array;
1338 if (printer_handles)
1339 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1340 (nb_printer_handles + 16) * sizeof(*new_array) );
1341 else
1342 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1343 (nb_printer_handles + 16) * sizeof(*new_array) );
1345 if (!new_array)
1347 handle = 0;
1348 goto end;
1350 printer_handles = new_array;
1351 nb_printer_handles += 16;
1354 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1356 handle = 0;
1357 goto end;
1361 /* clone the base name. This is NULL for the printserver */
1362 printer->printername = strdupW(printername);
1364 /* clone the full name */
1365 printer->name = strdupW(name);
1366 if (name && (!printer->name)) {
1367 handle = 0;
1368 goto end;
1371 if (printername) {
1372 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1373 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1374 /* OpenPrinter(",XcvMonitor " detected */
1375 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1376 printer->pm = monitor_load(&printername[len], NULL);
1377 if (printer->pm == NULL) {
1378 SetLastError(ERROR_UNKNOWN_PORT);
1379 handle = 0;
1380 goto end;
1383 else
1385 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1386 if (strncmpW( printername, XcvPortW, len) == 0) {
1387 /* OpenPrinter(",XcvPort " detected */
1388 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1389 printer->pm = monitor_load_by_port(&printername[len]);
1390 if (printer->pm == NULL) {
1391 SetLastError(ERROR_UNKNOWN_PORT);
1392 handle = 0;
1393 goto end;
1398 if (printer->pm) {
1399 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1400 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1401 pDefault ? pDefault->DesiredAccess : 0,
1402 &printer->hXcv);
1404 if (printer->hXcv == NULL) {
1405 SetLastError(ERROR_INVALID_PARAMETER);
1406 handle = 0;
1407 goto end;
1410 else
1412 /* Does the Printer exist? */
1413 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1414 ERR("Can't create Printers key\n");
1415 handle = 0;
1416 goto end;
1418 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1419 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1420 RegCloseKey(hkeyPrinters);
1421 SetLastError(ERROR_INVALID_PRINTER_NAME);
1422 handle = 0;
1423 goto end;
1425 RegCloseKey(hkeyPrinter);
1426 RegCloseKey(hkeyPrinters);
1429 else
1431 TRACE("using the local printserver\n");
1434 if(queue)
1435 printer->queue = queue;
1436 else
1438 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1439 if (!printer->queue) {
1440 handle = 0;
1441 goto end;
1443 list_init(&printer->queue->jobs);
1444 printer->queue->ref = 0;
1446 InterlockedIncrement(&printer->queue->ref);
1448 printer_handles[handle] = printer;
1449 handle++;
1450 end:
1451 LeaveCriticalSection(&printer_handles_cs);
1452 if (!handle && printer) {
1453 /* Something failed: Free all resources */
1454 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1455 monitor_unload(printer->pm);
1456 HeapFree(GetProcessHeap(), 0, printer->printername);
1457 HeapFree(GetProcessHeap(), 0, printer->name);
1458 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1459 HeapFree(GetProcessHeap(), 0, printer);
1462 return (HANDLE)handle;
1465 /******************************************************************
1466 * get_opened_printer
1467 * Get the pointer to the opened printer referred by the handle
1469 static opened_printer_t *get_opened_printer(HANDLE hprn)
1471 UINT_PTR idx = (UINT_PTR)hprn;
1472 opened_printer_t *ret = NULL;
1474 EnterCriticalSection(&printer_handles_cs);
1476 if ((idx <= 0) || (idx > nb_printer_handles))
1477 goto end;
1479 ret = printer_handles[idx - 1];
1480 end:
1481 LeaveCriticalSection(&printer_handles_cs);
1482 return ret;
1485 /******************************************************************
1486 * get_opened_printer_name
1487 * Get the pointer to the opened printer name referred by the handle
1489 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1491 opened_printer_t *printer = get_opened_printer(hprn);
1492 if(!printer) return NULL;
1493 return printer->name;
1496 /******************************************************************
1497 * WINSPOOL_GetOpenedPrinterRegKey
1500 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1502 LPCWSTR name = get_opened_printer_name(hPrinter);
1503 DWORD ret;
1504 HKEY hkeyPrinters;
1506 if(!name) return ERROR_INVALID_HANDLE;
1508 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1509 ERROR_SUCCESS)
1510 return ret;
1512 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1514 ERR("Can't find opened printer %s in registry\n",
1515 debugstr_w(name));
1516 RegCloseKey(hkeyPrinters);
1517 return ERROR_INVALID_PRINTER_NAME; /* ? */
1519 RegCloseKey(hkeyPrinters);
1520 return ERROR_SUCCESS;
1523 void WINSPOOL_LoadSystemPrinters(void)
1525 HKEY hkey, hkeyPrinters;
1526 HANDLE hprn;
1527 DWORD needed, num, i;
1528 WCHAR PrinterName[256];
1529 BOOL done = FALSE;
1531 /* This ensures that all printer entries have a valid Name value. If causes
1532 problems later if they don't. If one is found to be missed we create one
1533 and set it equal to the name of the key */
1534 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1535 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1536 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1537 for(i = 0; i < num; i++) {
1538 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
1539 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1540 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1541 set_reg_szW(hkey, NameW, PrinterName);
1543 RegCloseKey(hkey);
1548 RegCloseKey(hkeyPrinters);
1551 /* We want to avoid calling AddPrinter on printers as much as
1552 possible, because on cups printers this will (eventually) lead
1553 to a call to cupsGetPPD which takes forever, even with non-cups
1554 printers AddPrinter takes a while. So we'll tag all printers that
1555 were automatically added last time around, if they still exist
1556 we'll leave them be otherwise we'll delete them. */
1557 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1558 if(needed) {
1559 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1560 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1561 for(i = 0; i < num; i++) {
1562 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1563 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1564 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1565 DWORD dw = 1;
1566 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1567 RegCloseKey(hkey);
1569 ClosePrinter(hprn);
1574 HeapFree(GetProcessHeap(), 0, pi);
1578 #ifdef SONAME_LIBCUPS
1579 done = CUPS_LoadPrinters();
1580 #endif
1582 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1583 PRINTCAP_LoadPrinters();
1585 /* Now enumerate the list again and delete any printers that a still tagged */
1586 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1587 if(needed) {
1588 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1589 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1590 for(i = 0; i < num; i++) {
1591 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1592 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1593 BOOL delete_driver = FALSE;
1594 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1595 DWORD dw, type, size = sizeof(dw);
1596 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1597 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1598 DeletePrinter(hprn);
1599 delete_driver = TRUE;
1601 RegCloseKey(hkey);
1603 ClosePrinter(hprn);
1604 if(delete_driver)
1605 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1610 HeapFree(GetProcessHeap(), 0, pi);
1613 return;
1617 /******************************************************************
1618 * get_job
1620 * Get the pointer to the specified job.
1621 * Should hold the printer_handles_cs before calling.
1623 static job_t *get_job(HANDLE hprn, DWORD JobId)
1625 opened_printer_t *printer = get_opened_printer(hprn);
1626 job_t *job;
1628 if(!printer) return NULL;
1629 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1631 if(job->job_id == JobId)
1632 return job;
1634 return NULL;
1637 /***********************************************************
1638 * DEVMODEcpyAtoW
1640 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1642 BOOL Formname;
1643 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1644 DWORD size;
1646 Formname = (dmA->dmSize > off_formname);
1647 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1648 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1649 dmW->dmDeviceName, CCHDEVICENAME);
1650 if(!Formname) {
1651 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1652 dmA->dmSize - CCHDEVICENAME);
1653 } else {
1654 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1655 off_formname - CCHDEVICENAME);
1656 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1657 dmW->dmFormName, CCHFORMNAME);
1658 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1659 (off_formname + CCHFORMNAME));
1661 dmW->dmSize = size;
1662 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1663 dmA->dmDriverExtra);
1664 return dmW;
1667 /***********************************************************
1668 * DEVMODEdupWtoA
1669 * Creates an ascii copy of supplied devmode on heap
1671 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
1673 LPDEVMODEA dmA;
1674 DWORD size;
1675 BOOL Formname;
1676 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
1678 if(!dmW) return NULL;
1679 Formname = (dmW->dmSize > off_formname);
1680 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
1681 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1682 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1683 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1684 if(!Formname) {
1685 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1686 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
1687 } else {
1688 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1689 off_formname - CCHDEVICENAME * sizeof(WCHAR));
1690 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1691 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1692 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
1693 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
1695 dmA->dmSize = size;
1696 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
1697 dmW->dmDriverExtra);
1698 return dmA;
1701 /***********************************************************
1702 * PRINTER_INFO_2AtoW
1703 * Creates a unicode copy of PRINTER_INFO_2A on heap
1705 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1707 LPPRINTER_INFO_2W piW;
1708 UNICODE_STRING usBuffer;
1710 if(!piA) return NULL;
1711 piW = HeapAlloc(heap, 0, sizeof(*piW));
1712 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1714 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1715 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1716 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1717 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1718 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1719 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1720 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1721 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1722 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1723 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1724 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1725 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1726 return piW;
1729 /***********************************************************
1730 * FREE_PRINTER_INFO_2W
1731 * Free PRINTER_INFO_2W and all strings
1733 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1735 if(!piW) return;
1737 HeapFree(heap,0,piW->pServerName);
1738 HeapFree(heap,0,piW->pPrinterName);
1739 HeapFree(heap,0,piW->pShareName);
1740 HeapFree(heap,0,piW->pPortName);
1741 HeapFree(heap,0,piW->pDriverName);
1742 HeapFree(heap,0,piW->pComment);
1743 HeapFree(heap,0,piW->pLocation);
1744 HeapFree(heap,0,piW->pDevMode);
1745 HeapFree(heap,0,piW->pSepFile);
1746 HeapFree(heap,0,piW->pPrintProcessor);
1747 HeapFree(heap,0,piW->pDatatype);
1748 HeapFree(heap,0,piW->pParameters);
1749 HeapFree(heap,0,piW);
1750 return;
1753 /******************************************************************
1754 * DeviceCapabilities [WINSPOOL.@]
1755 * DeviceCapabilitiesA [WINSPOOL.@]
1758 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1759 LPSTR pOutput, LPDEVMODEA lpdm)
1761 INT ret;
1763 if (!GDI_CallDeviceCapabilities16)
1765 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1766 (LPCSTR)104 );
1767 if (!GDI_CallDeviceCapabilities16) return -1;
1769 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1771 /* If DC_PAPERSIZE map POINT16s to POINTs */
1772 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1773 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1774 POINT *pt = (POINT *)pOutput;
1775 INT i;
1776 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1777 for(i = 0; i < ret; i++, pt++)
1779 pt->x = tmp[i].x;
1780 pt->y = tmp[i].y;
1782 HeapFree( GetProcessHeap(), 0, tmp );
1784 return ret;
1788 /*****************************************************************************
1789 * DeviceCapabilitiesW [WINSPOOL.@]
1791 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1794 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1795 WORD fwCapability, LPWSTR pOutput,
1796 const DEVMODEW *pDevMode)
1798 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
1799 LPSTR pDeviceA = strdupWtoA(pDevice);
1800 LPSTR pPortA = strdupWtoA(pPort);
1801 INT ret;
1803 if(pOutput && (fwCapability == DC_BINNAMES ||
1804 fwCapability == DC_FILEDEPENDENCIES ||
1805 fwCapability == DC_PAPERNAMES)) {
1806 /* These need A -> W translation */
1807 INT size = 0, i;
1808 LPSTR pOutputA;
1809 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1810 dmA);
1811 if(ret == -1)
1812 return ret;
1813 switch(fwCapability) {
1814 case DC_BINNAMES:
1815 size = 24;
1816 break;
1817 case DC_PAPERNAMES:
1818 case DC_FILEDEPENDENCIES:
1819 size = 64;
1820 break;
1822 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1823 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1824 dmA);
1825 for(i = 0; i < ret; i++)
1826 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1827 pOutput + (i * size), size);
1828 HeapFree(GetProcessHeap(), 0, pOutputA);
1829 } else {
1830 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1831 (LPSTR)pOutput, dmA);
1833 HeapFree(GetProcessHeap(),0,pPortA);
1834 HeapFree(GetProcessHeap(),0,pDeviceA);
1835 HeapFree(GetProcessHeap(),0,dmA);
1836 return ret;
1839 /******************************************************************
1840 * DocumentPropertiesA [WINSPOOL.@]
1842 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1844 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1845 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1846 LPDEVMODEA pDevModeInput,DWORD fMode )
1848 LPSTR lpName = pDeviceName;
1849 static CHAR port[] = "LPT1:";
1850 LONG ret;
1852 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1853 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1856 if(!pDeviceName) {
1857 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1858 if(!lpNameW) {
1859 ERR("no name from hPrinter?\n");
1860 SetLastError(ERROR_INVALID_HANDLE);
1861 return -1;
1863 lpName = strdupWtoA(lpNameW);
1866 if (!GDI_CallExtDeviceMode16)
1868 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1869 (LPCSTR)102 );
1870 if (!GDI_CallExtDeviceMode16) {
1871 ERR("No CallExtDeviceMode16?\n");
1872 return -1;
1875 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1876 pDevModeInput, NULL, fMode);
1878 if(!pDeviceName)
1879 HeapFree(GetProcessHeap(),0,lpName);
1880 return ret;
1884 /*****************************************************************************
1885 * DocumentPropertiesW (WINSPOOL.@)
1887 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1889 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1890 LPWSTR pDeviceName,
1891 LPDEVMODEW pDevModeOutput,
1892 LPDEVMODEW pDevModeInput, DWORD fMode)
1895 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1896 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1897 LPDEVMODEA pDevModeOutputA = NULL;
1898 LONG ret;
1900 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1901 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1902 fMode);
1903 if(pDevModeOutput) {
1904 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1905 if(ret < 0) return ret;
1906 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1908 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1909 pDevModeInputA, fMode);
1910 if(pDevModeOutput) {
1911 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1912 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1914 if(fMode == 0 && ret > 0)
1915 ret += (CCHDEVICENAME + CCHFORMNAME);
1916 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1917 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1918 return ret;
1921 /******************************************************************
1922 * OpenPrinterA [WINSPOOL.@]
1924 * See OpenPrinterW.
1927 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1928 LPPRINTER_DEFAULTSA pDefault)
1930 UNICODE_STRING lpPrinterNameW;
1931 UNICODE_STRING usBuffer;
1932 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1933 PWSTR pwstrPrinterNameW;
1934 BOOL ret;
1936 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1938 if(pDefault) {
1939 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1940 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1941 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1942 pDefaultW = &DefaultW;
1944 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1945 if(pDefault) {
1946 RtlFreeUnicodeString(&usBuffer);
1947 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1949 RtlFreeUnicodeString(&lpPrinterNameW);
1950 return ret;
1953 /******************************************************************
1954 * OpenPrinterW [WINSPOOL.@]
1956 * Open a Printer / Printserver or a Printer-Object
1958 * PARAMS
1959 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1960 * phPrinter [O] The resulting Handle is stored here
1961 * pDefault [I] PTR to Default Printer Settings or NULL
1963 * RETURNS
1964 * Success: TRUE
1965 * Failure: FALSE
1967 * NOTES
1968 * lpPrinterName is one of:
1969 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1970 *| Printer: "PrinterName"
1971 *| Printer-Object: "PrinterName,Job xxx"
1972 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1973 *| XcvPort: "Servername,XcvPort PortName"
1975 * BUGS
1976 *| Printer-Object not supported
1977 *| pDefaults is ignored
1980 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1983 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1984 if (pDefault) {
1985 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1986 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1989 if(!phPrinter) {
1990 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1991 SetLastError(ERROR_INVALID_PARAMETER);
1992 return FALSE;
1995 /* Get the unique handle of the printer or Printserver */
1996 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1997 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1998 return (*phPrinter != 0);
2001 /******************************************************************
2002 * AddMonitorA [WINSPOOL.@]
2004 * See AddMonitorW.
2007 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2009 LPWSTR nameW = NULL;
2010 INT len;
2011 BOOL res;
2012 LPMONITOR_INFO_2A mi2a;
2013 MONITOR_INFO_2W mi2w;
2015 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2016 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2017 mi2a ? debugstr_a(mi2a->pName) : NULL,
2018 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
2019 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
2021 if (Level != 2) {
2022 SetLastError(ERROR_INVALID_LEVEL);
2023 return FALSE;
2026 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2027 if (mi2a == NULL) {
2028 return FALSE;
2031 if (pName) {
2032 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2033 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2034 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2037 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2038 if (mi2a->pName) {
2039 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2040 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2041 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2043 if (mi2a->pEnvironment) {
2044 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2045 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2046 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2048 if (mi2a->pDLLName) {
2049 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2050 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2051 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2054 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2056 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2057 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2058 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2060 HeapFree(GetProcessHeap(), 0, nameW);
2061 return (res);
2064 /******************************************************************************
2065 * AddMonitorW [WINSPOOL.@]
2067 * Install a Printmonitor
2069 * PARAMS
2070 * pName [I] Servername or NULL (local Computer)
2071 * Level [I] Structure-Level (Must be 2)
2072 * pMonitors [I] PTR to MONITOR_INFO_2
2074 * RETURNS
2075 * Success: TRUE
2076 * Failure: FALSE
2078 * NOTES
2079 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2082 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2084 monitor_t * pm = NULL;
2085 LPMONITOR_INFO_2W mi2w;
2086 HKEY hroot = NULL;
2087 HKEY hentry = NULL;
2088 DWORD disposition;
2089 BOOL res = FALSE;
2091 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2092 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2093 mi2w ? debugstr_w(mi2w->pName) : NULL,
2094 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
2095 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
2097 if (Level != 2) {
2098 SetLastError(ERROR_INVALID_LEVEL);
2099 return FALSE;
2102 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2103 if (mi2w == NULL) {
2104 return FALSE;
2107 if (pName && (pName[0])) {
2108 FIXME("for server %s not implemented\n", debugstr_w(pName));
2109 SetLastError(ERROR_ACCESS_DENIED);
2110 return FALSE;
2114 if (!mi2w->pName || (! mi2w->pName[0])) {
2115 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
2116 SetLastError(ERROR_INVALID_PARAMETER);
2117 return FALSE;
2119 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
2120 WARN("Environment %s requested (we support only %s)\n",
2121 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
2122 SetLastError(ERROR_INVALID_ENVIRONMENT);
2123 return FALSE;
2126 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
2127 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
2128 SetLastError(ERROR_INVALID_PARAMETER);
2129 return FALSE;
2132 /* Load and initialize the monitor. SetLastError() is called on failure */
2133 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
2134 return FALSE;
2136 monitor_unload(pm);
2138 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2139 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2140 return FALSE;
2143 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
2144 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
2145 &disposition) == ERROR_SUCCESS) {
2147 /* Some installers set options for the port before calling AddMonitor.
2148 We query the "Driver" entry to verify that the monitor is installed,
2149 before we return an error.
2150 When a user installs two print monitors at the same time with the
2151 same name but with a different driver DLL and a task switch comes
2152 between RegQueryValueExW and RegSetValueExW, a race condition
2153 is possible but silently ignored. */
2155 DWORD namesize = 0;
2157 if ((disposition == REG_OPENED_EXISTING_KEY) &&
2158 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
2159 &namesize) == ERROR_SUCCESS)) {
2160 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
2161 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2162 9x: ERROR_ALREADY_EXISTS (183) */
2163 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
2165 else
2167 INT len;
2168 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
2169 res = (RegSetValueExW(hentry, DriverW, 0,
2170 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
2172 RegCloseKey(hentry);
2175 RegCloseKey(hroot);
2176 return (res);
2179 /******************************************************************
2180 * DeletePrinterDriverA [WINSPOOL.@]
2183 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2185 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2188 /******************************************************************
2189 * DeletePrinterDriverW [WINSPOOL.@]
2192 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2194 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2197 /******************************************************************
2198 * DeleteMonitorA [WINSPOOL.@]
2200 * See DeleteMonitorW.
2203 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2205 LPWSTR nameW = NULL;
2206 LPWSTR EnvironmentW = NULL;
2207 LPWSTR MonitorNameW = NULL;
2208 BOOL res;
2209 INT len;
2211 if (pName) {
2212 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2213 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2214 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2217 if (pEnvironment) {
2218 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2219 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2220 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2222 if (pMonitorName) {
2223 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2224 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2225 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2228 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2230 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2231 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2232 HeapFree(GetProcessHeap(), 0, nameW);
2233 return (res);
2236 /******************************************************************
2237 * DeleteMonitorW [WINSPOOL.@]
2239 * Delete a specific Printmonitor from a Printing-Environment
2241 * PARAMS
2242 * pName [I] Servername or NULL (local Computer)
2243 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2244 * pMonitorName [I] Name of the Monitor, that should be deleted
2246 * RETURNS
2247 * Success: TRUE
2248 * Failure: FALSE
2250 * NOTES
2251 * pEnvironment is ignored in Windows for the local Computer.
2255 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2257 HKEY hroot = NULL;
2259 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2260 debugstr_w(pMonitorName));
2262 if (pName && (pName[0])) {
2263 FIXME("for server %s not implemented\n", debugstr_w(pName));
2264 SetLastError(ERROR_ACCESS_DENIED);
2265 return FALSE;
2268 /* pEnvironment is ignored in Windows for the local Computer */
2270 if (!pMonitorName || !pMonitorName[0]) {
2271 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
2272 SetLastError(ERROR_INVALID_PARAMETER);
2273 return FALSE;
2276 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2277 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2278 return FALSE;
2281 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
2282 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
2283 RegCloseKey(hroot);
2284 return TRUE;
2287 WARN("monitor %s does not exist\n", debugstr_w(pMonitorName));
2288 RegCloseKey(hroot);
2290 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2291 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
2292 return (FALSE);
2295 /******************************************************************
2296 * DeletePortA [WINSPOOL.@]
2298 * See DeletePortW.
2301 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2303 LPWSTR nameW = NULL;
2304 LPWSTR portW = NULL;
2305 INT len;
2306 DWORD res;
2308 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2310 /* convert servername to unicode */
2311 if (pName) {
2312 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2313 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2314 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2317 /* convert portname to unicode */
2318 if (pPortName) {
2319 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2320 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2321 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2324 res = DeletePortW(nameW, hWnd, portW);
2325 HeapFree(GetProcessHeap(), 0, nameW);
2326 HeapFree(GetProcessHeap(), 0, portW);
2327 return res;
2330 /******************************************************************
2331 * DeletePortW [WINSPOOL.@]
2333 * Delete a specific Port
2335 * PARAMS
2336 * pName [I] Servername or NULL (local Computer)
2337 * hWnd [I] Handle to parent Window for the Dialog-Box
2338 * pPortName [I] Name of the Port, that should be deleted
2340 * RETURNS
2341 * Success: TRUE
2342 * Failure: FALSE
2345 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2347 monitor_t * pm;
2348 monitor_t * pui;
2349 DWORD res;
2351 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2353 if (pName && pName[0]) {
2354 SetLastError(ERROR_INVALID_PARAMETER);
2355 return FALSE;
2358 if (!pPortName) {
2359 SetLastError(RPC_X_NULL_REF_POINTER);
2360 return FALSE;
2363 /* an empty Portname is Invalid */
2364 if (!pPortName[0]) {
2365 SetLastError(ERROR_NOT_SUPPORTED);
2366 return FALSE;
2369 pm = monitor_load_by_port(pPortName);
2370 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2371 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2372 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2373 TRACE("got %d with %u\n", res, GetLastError());
2375 else
2377 pui = monitor_loadui(pm);
2378 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2379 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2380 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2381 TRACE("got %d with %u\n", res, GetLastError());
2383 else
2385 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2386 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
2388 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2389 SetLastError(ERROR_NOT_SUPPORTED);
2390 res = FALSE;
2392 monitor_unload(pui);
2394 monitor_unload(pm);
2396 TRACE("returning %d with %u\n", res, GetLastError());
2397 return res;
2400 /******************************************************************************
2401 * SetPrinterW [WINSPOOL.@]
2403 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2405 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2406 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2407 return FALSE;
2410 /******************************************************************************
2411 * WritePrinter [WINSPOOL.@]
2413 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2415 opened_printer_t *printer;
2416 BOOL ret = FALSE;
2418 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2420 EnterCriticalSection(&printer_handles_cs);
2421 printer = get_opened_printer(hPrinter);
2422 if(!printer)
2424 SetLastError(ERROR_INVALID_HANDLE);
2425 goto end;
2428 if(!printer->doc)
2430 SetLastError(ERROR_SPL_NO_STARTDOC);
2431 goto end;
2434 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2435 end:
2436 LeaveCriticalSection(&printer_handles_cs);
2437 return ret;
2440 /*****************************************************************************
2441 * AddFormA [WINSPOOL.@]
2443 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2445 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2446 return 1;
2449 /*****************************************************************************
2450 * AddFormW [WINSPOOL.@]
2452 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2454 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2455 return 1;
2458 /*****************************************************************************
2459 * AddJobA [WINSPOOL.@]
2461 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2463 BOOL ret;
2464 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2465 DWORD needed;
2467 if(Level != 1) {
2468 SetLastError(ERROR_INVALID_LEVEL);
2469 return FALSE;
2472 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2474 if(ret) {
2475 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2476 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2477 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2478 if(*pcbNeeded > cbBuf) {
2479 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2480 ret = FALSE;
2481 } else {
2482 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2483 addjobA->JobId = addjobW->JobId;
2484 addjobA->Path = (char *)(addjobA + 1);
2485 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2488 return ret;
2491 /*****************************************************************************
2492 * AddJobW [WINSPOOL.@]
2494 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2496 opened_printer_t *printer;
2497 job_t *job;
2498 BOOL ret = FALSE;
2499 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2500 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2501 WCHAR path[MAX_PATH], filename[MAX_PATH];
2502 DWORD len;
2503 ADDJOB_INFO_1W *addjob;
2505 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2507 EnterCriticalSection(&printer_handles_cs);
2509 printer = get_opened_printer(hPrinter);
2511 if(!printer) {
2512 SetLastError(ERROR_INVALID_HANDLE);
2513 goto end;
2516 if(Level != 1) {
2517 SetLastError(ERROR_INVALID_LEVEL);
2518 goto end;
2521 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2522 if(!job)
2523 goto end;
2525 job->job_id = InterlockedIncrement(&next_job_id);
2527 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2528 if(path[len - 1] != '\\')
2529 path[len++] = '\\';
2530 memcpy(path + len, spool_path, sizeof(spool_path));
2531 sprintfW(filename, fmtW, path, job->job_id);
2533 len = strlenW(filename);
2534 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2535 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2536 job->document_title = strdupW(default_doc_title);
2537 list_add_tail(&printer->queue->jobs, &job->entry);
2539 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2540 if(*pcbNeeded <= cbBuf) {
2541 addjob = (ADDJOB_INFO_1W*)pData;
2542 addjob->JobId = job->job_id;
2543 addjob->Path = (WCHAR *)(addjob + 1);
2544 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2545 ret = TRUE;
2546 } else
2547 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2549 end:
2550 LeaveCriticalSection(&printer_handles_cs);
2551 return ret;
2554 /*****************************************************************************
2555 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2557 * Return the PATH for the Print-Processors
2559 * See GetPrintProcessorDirectoryW.
2563 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2564 DWORD level, LPBYTE Info,
2565 DWORD cbBuf, LPDWORD pcbNeeded)
2567 LPWSTR serverW = NULL;
2568 LPWSTR envW = NULL;
2569 BOOL ret;
2570 INT len;
2572 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2573 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2576 if (server) {
2577 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2578 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2579 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2582 if (env) {
2583 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2584 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2585 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2588 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2589 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2591 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2592 cbBuf, pcbNeeded);
2594 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2595 cbBuf, NULL, NULL) > 0;
2598 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2599 HeapFree(GetProcessHeap(), 0, envW);
2600 HeapFree(GetProcessHeap(), 0, serverW);
2601 return ret;
2604 /*****************************************************************************
2605 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2607 * Return the PATH for the Print-Processors
2609 * PARAMS
2610 * server [I] Servername (NT only) or NULL (local Computer)
2611 * env [I] Printing-Environment (see below) or NULL (Default)
2612 * level [I] Structure-Level (must be 1)
2613 * Info [O] PTR to Buffer that receives the Result
2614 * cbBuf [I] Size of Buffer at "Info"
2615 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2616 * required for the Buffer at "Info"
2618 * RETURNS
2619 * Success: TRUE and in pcbNeeded the Bytes used in Info
2620 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2621 * if cbBuf is too small
2623 * Native Values returned in Info on Success:
2624 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2625 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2626 *| win9x(Windows 4.0): "%winsysdir%"
2628 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2630 * BUGS
2631 * Only NULL or "" is supported for server
2634 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2635 DWORD level, LPBYTE Info,
2636 DWORD cbBuf, LPDWORD pcbNeeded)
2638 DWORD needed;
2639 const printenv_t * env_t;
2641 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2642 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2644 if(server != NULL && server[0]) {
2645 FIXME("server not supported: %s\n", debugstr_w(server));
2646 SetLastError(ERROR_INVALID_PARAMETER);
2647 return FALSE;
2650 env_t = validate_envW(env);
2651 if(!env_t) return FALSE; /* environment invalid or unsupported */
2653 if(level != 1) {
2654 WARN("(Level: %d) is ignored in win9x\n", level);
2655 SetLastError(ERROR_INVALID_LEVEL);
2656 return FALSE;
2659 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2660 needed = GetSystemDirectoryW(NULL, 0);
2661 /* add the Size for the Subdirectories */
2662 needed += lstrlenW(spoolprtprocsW);
2663 needed += lstrlenW(env_t->subdir);
2664 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2666 if(pcbNeeded) *pcbNeeded = needed;
2667 TRACE ("required: 0x%x/%d\n", needed, needed);
2668 if (needed > cbBuf) {
2669 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2670 return FALSE;
2672 if(pcbNeeded == NULL) {
2673 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2674 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2675 SetLastError(RPC_X_NULL_REF_POINTER);
2676 return FALSE;
2678 if(Info == NULL) {
2679 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2680 SetLastError(RPC_X_NULL_REF_POINTER);
2681 return FALSE;
2684 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2685 /* add the Subdirectories */
2686 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2687 lstrcatW((LPWSTR) Info, env_t->subdir);
2688 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2689 return TRUE;
2692 /*****************************************************************************
2693 * WINSPOOL_OpenDriverReg [internal]
2695 * opens the registry for the printer drivers depending on the given input
2696 * variable pEnvironment
2698 * RETURNS:
2699 * the opened hkey on success
2700 * NULL on error
2702 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2704 HKEY retval = NULL;
2705 LPWSTR buffer;
2706 const printenv_t * env;
2708 TRACE("(%s, %d)\n",
2709 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2711 if (!pEnvironment || unicode) {
2712 /* pEnvironment was NULL or an Unicode-String: use it direct */
2713 env = validate_envW(pEnvironment);
2715 else
2717 /* pEnvironment was an ANSI-String: convert to unicode first */
2718 LPWSTR buffer;
2719 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2720 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2721 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2722 env = validate_envW(buffer);
2723 HeapFree(GetProcessHeap(), 0, buffer);
2725 if (!env) return NULL;
2727 buffer = HeapAlloc( GetProcessHeap(), 0,
2728 (strlenW(DriversW) + strlenW(env->envname) +
2729 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2730 if(buffer) {
2731 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2732 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2733 HeapFree(GetProcessHeap(), 0, buffer);
2735 return retval;
2738 /*****************************************************************************
2739 * AddPrinterW [WINSPOOL.@]
2741 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2743 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2744 LPDEVMODEA dmA;
2745 LPDEVMODEW dmW;
2746 HANDLE retval;
2747 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2748 LONG size;
2749 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2750 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2751 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2752 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2753 statusW[] = {'S','t','a','t','u','s',0},
2754 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2756 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2758 if(pName != NULL) {
2759 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2760 SetLastError(ERROR_INVALID_PARAMETER);
2761 return 0;
2763 if(Level != 2) {
2764 ERR("Level = %d, unsupported!\n", Level);
2765 SetLastError(ERROR_INVALID_LEVEL);
2766 return 0;
2768 if(!pPrinter) {
2769 SetLastError(ERROR_INVALID_PARAMETER);
2770 return 0;
2772 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2773 ERROR_SUCCESS) {
2774 ERR("Can't create Printers key\n");
2775 return 0;
2777 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2778 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2779 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2780 RegCloseKey(hkeyPrinter);
2781 RegCloseKey(hkeyPrinters);
2782 return 0;
2784 RegCloseKey(hkeyPrinter);
2786 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2787 if(!hkeyDrivers) {
2788 ERR("Can't create Drivers key\n");
2789 RegCloseKey(hkeyPrinters);
2790 return 0;
2792 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2793 ERROR_SUCCESS) {
2794 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2795 RegCloseKey(hkeyPrinters);
2796 RegCloseKey(hkeyDrivers);
2797 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2798 return 0;
2800 RegCloseKey(hkeyDriver);
2801 RegCloseKey(hkeyDrivers);
2803 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2804 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2805 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2806 RegCloseKey(hkeyPrinters);
2807 return 0;
2810 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2811 ERROR_SUCCESS) {
2812 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2813 SetLastError(ERROR_INVALID_PRINTER_NAME);
2814 RegCloseKey(hkeyPrinters);
2815 return 0;
2817 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2818 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2819 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2821 /* See if we can load the driver. We may need the devmode structure anyway
2823 * FIXME:
2824 * Note that DocumentPropertiesW will briefly try to open the printer we
2825 * just create to find a DEVMODEA struct (it will use the WINEPS default
2826 * one in case it is not there, so we are ok).
2828 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2830 if(size < 0) {
2831 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2832 size = sizeof(DEVMODEW);
2834 if(pi->pDevMode)
2835 dmW = pi->pDevMode;
2836 else
2838 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2839 dmW->dmSize = size;
2840 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2842 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2843 HeapFree(GetProcessHeap(),0,dmW);
2844 dmW=NULL;
2846 else
2848 /* set devmode to printer name */
2849 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2853 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2854 and we support these drivers. NT writes DEVMODEW so somehow
2855 we'll need to distinguish between these when we support NT
2856 drivers */
2857 if (dmW)
2859 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2860 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2861 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2862 HeapFree(GetProcessHeap(), 0, dmA);
2863 if(!pi->pDevMode)
2864 HeapFree(GetProcessHeap(), 0, dmW);
2866 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2867 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2868 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2869 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2871 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2872 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2873 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2874 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2875 (LPBYTE)&pi->Priority, sizeof(DWORD));
2876 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2877 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2878 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2879 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2880 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2881 (LPBYTE)&pi->Status, sizeof(DWORD));
2882 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2883 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2885 RegCloseKey(hkeyPrinter);
2886 RegCloseKey(hkeyPrinters);
2887 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2888 ERR("OpenPrinter failing\n");
2889 return 0;
2891 return retval;
2894 /*****************************************************************************
2895 * AddPrinterA [WINSPOOL.@]
2897 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2899 UNICODE_STRING pNameW;
2900 PWSTR pwstrNameW;
2901 PRINTER_INFO_2W *piW;
2902 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2903 HANDLE ret;
2905 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2906 if(Level != 2) {
2907 ERR("Level = %d, unsupported!\n", Level);
2908 SetLastError(ERROR_INVALID_LEVEL);
2909 return 0;
2911 pwstrNameW = asciitounicode(&pNameW,pName);
2912 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2914 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2916 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2917 RtlFreeUnicodeString(&pNameW);
2918 return ret;
2922 /*****************************************************************************
2923 * ClosePrinter [WINSPOOL.@]
2925 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2927 UINT_PTR i = (UINT_PTR)hPrinter;
2928 opened_printer_t *printer = NULL;
2929 BOOL ret = FALSE;
2931 TRACE("(%p)\n", hPrinter);
2933 EnterCriticalSection(&printer_handles_cs);
2935 if ((i > 0) && (i <= nb_printer_handles))
2936 printer = printer_handles[i - 1];
2939 if(printer)
2941 struct list *cursor, *cursor2;
2943 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer->pm,
2944 debugstr_w(printer->pm ? printer->pm->dllname : NULL),
2945 printer->hXcv, debugstr_w(printer->name), printer->doc );
2947 if(printer->doc)
2948 EndDocPrinter(hPrinter);
2950 if(InterlockedDecrement(&printer->queue->ref) == 0)
2952 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2954 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2955 ScheduleJob(hPrinter, job->job_id);
2957 HeapFree(GetProcessHeap(), 0, printer->queue);
2959 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
2960 monitor_unload(printer->pm);
2961 HeapFree(GetProcessHeap(), 0, printer->printername);
2962 HeapFree(GetProcessHeap(), 0, printer->name);
2963 HeapFree(GetProcessHeap(), 0, printer);
2964 printer_handles[i - 1] = NULL;
2965 ret = TRUE;
2967 LeaveCriticalSection(&printer_handles_cs);
2968 return ret;
2971 /*****************************************************************************
2972 * DeleteFormA [WINSPOOL.@]
2974 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2976 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2977 return 1;
2980 /*****************************************************************************
2981 * DeleteFormW [WINSPOOL.@]
2983 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2985 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2986 return 1;
2989 /*****************************************************************************
2990 * DeletePrinter [WINSPOOL.@]
2992 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2994 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2995 HKEY hkeyPrinters, hkey;
2997 if(!lpNameW) {
2998 SetLastError(ERROR_INVALID_HANDLE);
2999 return FALSE;
3001 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3002 RegDeleteTreeW(hkeyPrinters, lpNameW);
3003 RegCloseKey(hkeyPrinters);
3005 WriteProfileStringW(devicesW, lpNameW, NULL);
3006 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3007 RegDeleteValueW(hkey, lpNameW);
3008 RegCloseKey(hkey);
3010 return TRUE;
3013 /*****************************************************************************
3014 * SetPrinterA [WINSPOOL.@]
3016 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3017 DWORD Command)
3019 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
3020 return FALSE;
3023 /*****************************************************************************
3024 * SetJobA [WINSPOOL.@]
3026 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3027 LPBYTE pJob, DWORD Command)
3029 BOOL ret;
3030 LPBYTE JobW;
3031 UNICODE_STRING usBuffer;
3033 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3035 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3036 are all ignored by SetJob, so we don't bother copying them */
3037 switch(Level)
3039 case 0:
3040 JobW = NULL;
3041 break;
3042 case 1:
3044 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3045 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3047 JobW = (LPBYTE)info1W;
3048 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3049 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3050 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3051 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3052 info1W->Status = info1A->Status;
3053 info1W->Priority = info1A->Priority;
3054 info1W->Position = info1A->Position;
3055 info1W->PagesPrinted = info1A->PagesPrinted;
3056 break;
3058 case 2:
3060 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3061 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3063 JobW = (LPBYTE)info2W;
3064 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3065 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3066 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3067 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3068 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3069 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3070 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3071 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3072 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3073 info2W->Status = info2A->Status;
3074 info2W->Priority = info2A->Priority;
3075 info2W->Position = info2A->Position;
3076 info2W->StartTime = info2A->StartTime;
3077 info2W->UntilTime = info2A->UntilTime;
3078 info2W->PagesPrinted = info2A->PagesPrinted;
3079 break;
3081 case 3:
3082 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3083 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3084 break;
3085 default:
3086 SetLastError(ERROR_INVALID_LEVEL);
3087 return FALSE;
3090 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3092 switch(Level)
3094 case 1:
3096 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3097 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3098 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3099 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3100 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3101 break;
3103 case 2:
3105 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3106 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3107 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3108 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3109 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3110 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3111 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3112 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3113 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3114 break;
3117 HeapFree(GetProcessHeap(), 0, JobW);
3119 return ret;
3122 /*****************************************************************************
3123 * SetJobW [WINSPOOL.@]
3125 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3126 LPBYTE pJob, DWORD Command)
3128 BOOL ret = FALSE;
3129 job_t *job;
3131 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3132 FIXME("Ignoring everything other than document title\n");
3134 EnterCriticalSection(&printer_handles_cs);
3135 job = get_job(hPrinter, JobId);
3136 if(!job)
3137 goto end;
3139 switch(Level)
3141 case 0:
3142 break;
3143 case 1:
3145 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3146 HeapFree(GetProcessHeap(), 0, job->document_title);
3147 job->document_title = strdupW(info1->pDocument);
3148 break;
3150 case 2:
3152 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3153 HeapFree(GetProcessHeap(), 0, job->document_title);
3154 job->document_title = strdupW(info2->pDocument);
3155 break;
3157 case 3:
3158 break;
3159 default:
3160 SetLastError(ERROR_INVALID_LEVEL);
3161 goto end;
3163 ret = TRUE;
3164 end:
3165 LeaveCriticalSection(&printer_handles_cs);
3166 return ret;
3169 /*****************************************************************************
3170 * EndDocPrinter [WINSPOOL.@]
3172 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3174 opened_printer_t *printer;
3175 BOOL ret = FALSE;
3176 TRACE("(%p)\n", hPrinter);
3178 EnterCriticalSection(&printer_handles_cs);
3180 printer = get_opened_printer(hPrinter);
3181 if(!printer)
3183 SetLastError(ERROR_INVALID_HANDLE);
3184 goto end;
3187 if(!printer->doc)
3189 SetLastError(ERROR_SPL_NO_STARTDOC);
3190 goto end;
3193 CloseHandle(printer->doc->hf);
3194 ScheduleJob(hPrinter, printer->doc->job_id);
3195 HeapFree(GetProcessHeap(), 0, printer->doc);
3196 printer->doc = NULL;
3197 ret = TRUE;
3198 end:
3199 LeaveCriticalSection(&printer_handles_cs);
3200 return ret;
3203 /*****************************************************************************
3204 * EndPagePrinter [WINSPOOL.@]
3206 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3208 FIXME("(%p): stub\n", hPrinter);
3209 return TRUE;
3212 /*****************************************************************************
3213 * StartDocPrinterA [WINSPOOL.@]
3215 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3217 UNICODE_STRING usBuffer;
3218 DOC_INFO_2W doc2W;
3219 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3220 DWORD ret;
3222 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3223 or one (DOC_INFO_3) extra DWORDs */
3225 switch(Level) {
3226 case 2:
3227 doc2W.JobId = doc2->JobId;
3228 /* fall through */
3229 case 3:
3230 doc2W.dwMode = doc2->dwMode;
3231 /* fall through */
3232 case 1:
3233 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3234 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3235 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3236 break;
3238 default:
3239 SetLastError(ERROR_INVALID_LEVEL);
3240 return FALSE;
3243 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3245 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3246 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3247 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3249 return ret;
3252 /*****************************************************************************
3253 * StartDocPrinterW [WINSPOOL.@]
3255 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3257 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3258 opened_printer_t *printer;
3259 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3260 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3261 JOB_INFO_1W job_info;
3262 DWORD needed, ret = 0;
3263 HANDLE hf;
3264 WCHAR *filename;
3266 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3267 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3268 debugstr_w(doc->pDatatype));
3270 if(Level < 1 || Level > 3)
3272 SetLastError(ERROR_INVALID_LEVEL);
3273 return 0;
3276 EnterCriticalSection(&printer_handles_cs);
3277 printer = get_opened_printer(hPrinter);
3278 if(!printer)
3280 SetLastError(ERROR_INVALID_HANDLE);
3281 goto end;
3284 if(printer->doc)
3286 SetLastError(ERROR_INVALID_PRINTER_STATE);
3287 goto end;
3290 /* Even if we're printing to a file we still add a print job, we'll
3291 just ignore the spool file name */
3293 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3295 ERR("AddJob failed gle %u\n", GetLastError());
3296 goto end;
3299 if(doc->pOutputFile)
3300 filename = doc->pOutputFile;
3301 else
3302 filename = addjob->Path;
3304 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3305 if(hf == INVALID_HANDLE_VALUE)
3306 goto end;
3308 memset(&job_info, 0, sizeof(job_info));
3309 job_info.pDocument = doc->pDocName;
3310 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3312 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3313 printer->doc->hf = hf;
3314 ret = printer->doc->job_id = addjob->JobId;
3315 end:
3316 LeaveCriticalSection(&printer_handles_cs);
3318 return ret;
3321 /*****************************************************************************
3322 * StartPagePrinter [WINSPOOL.@]
3324 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3326 FIXME("(%p): stub\n", hPrinter);
3327 return TRUE;
3330 /*****************************************************************************
3331 * GetFormA [WINSPOOL.@]
3333 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3334 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3336 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3337 Level,pForm,cbBuf,pcbNeeded);
3338 return FALSE;
3341 /*****************************************************************************
3342 * GetFormW [WINSPOOL.@]
3344 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3345 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3347 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3348 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3349 return FALSE;
3352 /*****************************************************************************
3353 * SetFormA [WINSPOOL.@]
3355 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3356 LPBYTE pForm)
3358 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3359 return FALSE;
3362 /*****************************************************************************
3363 * SetFormW [WINSPOOL.@]
3365 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3366 LPBYTE pForm)
3368 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3369 return FALSE;
3372 /*****************************************************************************
3373 * ReadPrinter [WINSPOOL.@]
3375 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3376 LPDWORD pNoBytesRead)
3378 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3379 return FALSE;
3382 /*****************************************************************************
3383 * ResetPrinterA [WINSPOOL.@]
3385 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3387 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3388 return FALSE;
3391 /*****************************************************************************
3392 * ResetPrinterW [WINSPOOL.@]
3394 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3396 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3397 return FALSE;
3400 /*****************************************************************************
3401 * WINSPOOL_GetDWORDFromReg
3403 * Return DWORD associated with ValueName from hkey.
3405 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3407 DWORD sz = sizeof(DWORD), type, value = 0;
3408 LONG ret;
3410 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3412 if(ret != ERROR_SUCCESS) {
3413 WARN("Got ret = %d on name %s\n", ret, ValueName);
3414 return 0;
3416 if(type != REG_DWORD) {
3417 ERR("Got type %d\n", type);
3418 return 0;
3420 return value;
3424 /*****************************************************************************
3425 * get_filename_from_reg [internal]
3427 * Get ValueName from hkey storing result in out
3428 * when the Value in the registry has only a filename, use driverdir as prefix
3429 * outlen is space left in out
3430 * String is stored either as unicode or ascii
3434 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3435 LPBYTE out, DWORD outlen, LPDWORD needed, BOOL unicode)
3437 WCHAR filename[MAX_PATH];
3438 DWORD size;
3439 DWORD type;
3440 LONG ret;
3441 LPWSTR buffer = filename;
3442 LPWSTR ptr;
3444 *needed = 0;
3445 size = sizeof(filename);
3446 buffer[0] = '\0';
3447 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3448 if (ret == ERROR_MORE_DATA) {
3449 TRACE("need dynamic buffer: %u\n", size);
3450 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3451 if (!buffer) {
3452 /* No Memory is bad */
3453 return FALSE;
3455 buffer[0] = '\0';
3456 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3459 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3460 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3461 return FALSE;
3464 ptr = buffer;
3465 while (ptr) {
3466 /* do we have a full path ? */
3467 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3468 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3470 if (!ret) {
3471 /* we must build the full Path */
3472 *needed += dirlen;
3473 if ((out) && (outlen > dirlen)) {
3474 if (unicode) {
3475 lstrcpyW((LPWSTR)out, driverdir);
3477 else
3479 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, (LPSTR)out, outlen, NULL, NULL);
3481 out += dirlen;
3482 outlen -= dirlen;
3484 else
3485 out = NULL;
3488 /* write the filename */
3489 if (unicode) {
3490 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3491 if ((out) && (outlen >= size)) {
3492 lstrcpyW((LPWSTR)out, ptr);
3493 out += size;
3494 outlen -= size;
3496 else
3497 out = NULL;
3499 else
3501 size = WideCharToMultiByte(CP_ACP, 0, ptr, -1, NULL, 0, NULL, NULL);
3502 if ((out) && (outlen >= size)) {
3503 WideCharToMultiByte(CP_ACP, 0, ptr, -1, (LPSTR)out, outlen, NULL, NULL);
3504 out += size;
3505 outlen -= size;
3507 else
3508 out = NULL;
3510 *needed += size;
3511 ptr += lstrlenW(ptr)+1;
3512 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3515 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3517 /* write the multisz-termination */
3518 if (type == REG_MULTI_SZ) {
3519 size = (unicode) ? sizeof(WCHAR) : 1;
3521 *needed += size;
3522 if (out && (outlen >= size)) {
3523 memset (out, 0, size);
3526 return TRUE;
3529 /*****************************************************************************
3530 * WINSPOOL_GetStringFromReg
3532 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3533 * String is stored either as unicode or ascii.
3534 * Bit of a hack here to get the ValueName if we want ascii.
3536 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3537 DWORD buflen, DWORD *needed,
3538 BOOL unicode)
3540 DWORD sz = buflen, type;
3541 LONG ret;
3543 if(unicode)
3544 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3545 else {
3546 LPSTR ValueNameA = strdupWtoA(ValueName);
3547 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3548 HeapFree(GetProcessHeap(),0,ValueNameA);
3550 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3551 WARN("Got ret = %d\n", ret);
3552 *needed = 0;
3553 return FALSE;
3555 /* add space for terminating '\0' */
3556 sz += unicode ? sizeof(WCHAR) : 1;
3557 *needed = sz;
3559 if (ptr)
3560 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3562 return TRUE;
3565 /*****************************************************************************
3566 * WINSPOOL_GetDefaultDevMode
3568 * Get a default DevMode values for wineps.
3569 * FIXME - use ppd.
3572 static void WINSPOOL_GetDefaultDevMode(
3573 LPBYTE ptr,
3574 DWORD buflen, DWORD *needed,
3575 BOOL unicode)
3577 DEVMODEA dm;
3578 static const char szwps[] = "wineps.drv";
3580 /* fill default DEVMODE - should be read from ppd... */
3581 ZeroMemory( &dm, sizeof(dm) );
3582 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3583 dm.dmSpecVersion = DM_SPECVERSION;
3584 dm.dmDriverVersion = 1;
3585 dm.dmSize = sizeof(DEVMODEA);
3586 dm.dmDriverExtra = 0;
3587 dm.dmFields =
3588 DM_ORIENTATION | DM_PAPERSIZE |
3589 DM_PAPERLENGTH | DM_PAPERWIDTH |
3590 DM_SCALE |
3591 DM_COPIES |
3592 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3593 DM_YRESOLUTION | DM_TTOPTION;
3595 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3596 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3597 dm.u1.s1.dmPaperLength = 2970;
3598 dm.u1.s1.dmPaperWidth = 2100;
3600 dm.dmScale = 100;
3601 dm.dmCopies = 1;
3602 dm.dmDefaultSource = DMBIN_AUTO;
3603 dm.dmPrintQuality = DMRES_MEDIUM;
3604 /* dm.dmColor */
3605 /* dm.dmDuplex */
3606 dm.dmYResolution = 300; /* 300dpi */
3607 dm.dmTTOption = DMTT_BITMAP;
3608 /* dm.dmCollate */
3609 /* dm.dmFormName */
3610 /* dm.dmLogPixels */
3611 /* dm.dmBitsPerPel */
3612 /* dm.dmPelsWidth */
3613 /* dm.dmPelsHeight */
3614 /* dm.dmDisplayFlags */
3615 /* dm.dmDisplayFrequency */
3616 /* dm.dmICMMethod */
3617 /* dm.dmICMIntent */
3618 /* dm.dmMediaType */
3619 /* dm.dmDitherType */
3620 /* dm.dmReserved1 */
3621 /* dm.dmReserved2 */
3622 /* dm.dmPanningWidth */
3623 /* dm.dmPanningHeight */
3625 if(unicode) {
3626 if(buflen >= sizeof(DEVMODEW)) {
3627 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3628 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3629 HeapFree(GetProcessHeap(),0,pdmW);
3631 *needed = sizeof(DEVMODEW);
3633 else
3635 if(buflen >= sizeof(DEVMODEA)) {
3636 memcpy(ptr, &dm, sizeof(DEVMODEA));
3638 *needed = sizeof(DEVMODEA);
3642 /*****************************************************************************
3643 * WINSPOOL_GetDevModeFromReg
3645 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3646 * DevMode is stored either as unicode or ascii.
3648 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3649 LPBYTE ptr,
3650 DWORD buflen, DWORD *needed,
3651 BOOL unicode)
3653 DWORD sz = buflen, type;
3654 LONG ret;
3656 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3657 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3658 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3659 if (sz < sizeof(DEVMODEA))
3661 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3662 return FALSE;
3664 /* ensures that dmSize is not erratically bogus if registry is invalid */
3665 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3666 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3667 if(unicode) {
3668 sz += (CCHDEVICENAME + CCHFORMNAME);
3669 if(buflen >= sz) {
3670 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3671 memcpy(ptr, dmW, sz);
3672 HeapFree(GetProcessHeap(),0,dmW);
3675 *needed = sz;
3676 return TRUE;
3679 /*********************************************************************
3680 * WINSPOOL_GetPrinter_1
3682 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3683 * The strings are either stored as unicode or ascii.
3685 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3686 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3687 BOOL unicode)
3689 DWORD size, left = cbBuf;
3690 BOOL space = (cbBuf > 0);
3691 LPBYTE ptr = buf;
3693 *pcbNeeded = 0;
3695 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3696 unicode)) {
3697 if(space && size <= left) {
3698 pi1->pName = (LPWSTR)ptr;
3699 ptr += size;
3700 left -= size;
3701 } else
3702 space = FALSE;
3703 *pcbNeeded += size;
3706 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3707 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3708 unicode)) {
3709 if(space && size <= left) {
3710 pi1->pDescription = (LPWSTR)ptr;
3711 ptr += size;
3712 left -= size;
3713 } else
3714 space = FALSE;
3715 *pcbNeeded += size;
3718 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3719 unicode)) {
3720 if(space && size <= left) {
3721 pi1->pComment = (LPWSTR)ptr;
3722 ptr += size;
3723 left -= size;
3724 } else
3725 space = FALSE;
3726 *pcbNeeded += size;
3729 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3731 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3732 memset(pi1, 0, sizeof(*pi1));
3734 return space;
3736 /*********************************************************************
3737 * WINSPOOL_GetPrinter_2
3739 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3740 * The strings are either stored as unicode or ascii.
3742 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3743 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3744 BOOL unicode)
3746 DWORD size, left = cbBuf;
3747 BOOL space = (cbBuf > 0);
3748 LPBYTE ptr = buf;
3750 *pcbNeeded = 0;
3752 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3753 unicode)) {
3754 if(space && size <= left) {
3755 pi2->pPrinterName = (LPWSTR)ptr;
3756 ptr += size;
3757 left -= size;
3758 } else
3759 space = FALSE;
3760 *pcbNeeded += size;
3762 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3763 unicode)) {
3764 if(space && size <= left) {
3765 pi2->pShareName = (LPWSTR)ptr;
3766 ptr += size;
3767 left -= size;
3768 } else
3769 space = FALSE;
3770 *pcbNeeded += size;
3772 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3773 unicode)) {
3774 if(space && size <= left) {
3775 pi2->pPortName = (LPWSTR)ptr;
3776 ptr += size;
3777 left -= size;
3778 } else
3779 space = FALSE;
3780 *pcbNeeded += size;
3782 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3783 &size, unicode)) {
3784 if(space && size <= left) {
3785 pi2->pDriverName = (LPWSTR)ptr;
3786 ptr += size;
3787 left -= size;
3788 } else
3789 space = FALSE;
3790 *pcbNeeded += size;
3792 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3793 unicode)) {
3794 if(space && size <= left) {
3795 pi2->pComment = (LPWSTR)ptr;
3796 ptr += size;
3797 left -= size;
3798 } else
3799 space = FALSE;
3800 *pcbNeeded += size;
3802 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3803 unicode)) {
3804 if(space && size <= left) {
3805 pi2->pLocation = (LPWSTR)ptr;
3806 ptr += size;
3807 left -= size;
3808 } else
3809 space = FALSE;
3810 *pcbNeeded += size;
3812 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3813 &size, unicode)) {
3814 if(space && size <= left) {
3815 pi2->pDevMode = (LPDEVMODEW)ptr;
3816 ptr += size;
3817 left -= size;
3818 } else
3819 space = FALSE;
3820 *pcbNeeded += size;
3822 else
3824 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3825 if(space && size <= left) {
3826 pi2->pDevMode = (LPDEVMODEW)ptr;
3827 ptr += size;
3828 left -= size;
3829 } else
3830 space = FALSE;
3831 *pcbNeeded += size;
3833 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3834 &size, unicode)) {
3835 if(space && size <= left) {
3836 pi2->pSepFile = (LPWSTR)ptr;
3837 ptr += size;
3838 left -= size;
3839 } else
3840 space = FALSE;
3841 *pcbNeeded += size;
3843 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3844 &size, unicode)) {
3845 if(space && size <= left) {
3846 pi2->pPrintProcessor = (LPWSTR)ptr;
3847 ptr += size;
3848 left -= size;
3849 } else
3850 space = FALSE;
3851 *pcbNeeded += size;
3853 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3854 &size, unicode)) {
3855 if(space && size <= left) {
3856 pi2->pDatatype = (LPWSTR)ptr;
3857 ptr += size;
3858 left -= size;
3859 } else
3860 space = FALSE;
3861 *pcbNeeded += size;
3863 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3864 &size, unicode)) {
3865 if(space && size <= left) {
3866 pi2->pParameters = (LPWSTR)ptr;
3867 ptr += size;
3868 left -= size;
3869 } else
3870 space = FALSE;
3871 *pcbNeeded += size;
3873 if(pi2) {
3874 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3875 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3876 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3877 "Default Priority");
3878 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3879 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3882 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3883 memset(pi2, 0, sizeof(*pi2));
3885 return space;
3888 /*********************************************************************
3889 * WINSPOOL_GetPrinter_4
3891 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3893 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3894 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3895 BOOL unicode)
3897 DWORD size, left = cbBuf;
3898 BOOL space = (cbBuf > 0);
3899 LPBYTE ptr = buf;
3901 *pcbNeeded = 0;
3903 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3904 unicode)) {
3905 if(space && size <= left) {
3906 pi4->pPrinterName = (LPWSTR)ptr;
3907 ptr += size;
3908 left -= size;
3909 } else
3910 space = FALSE;
3911 *pcbNeeded += size;
3913 if(pi4) {
3914 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3917 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3918 memset(pi4, 0, sizeof(*pi4));
3920 return space;
3923 /*********************************************************************
3924 * WINSPOOL_GetPrinter_5
3926 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3928 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3929 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3930 BOOL unicode)
3932 DWORD size, left = cbBuf;
3933 BOOL space = (cbBuf > 0);
3934 LPBYTE ptr = buf;
3936 *pcbNeeded = 0;
3938 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3939 unicode)) {
3940 if(space && size <= left) {
3941 pi5->pPrinterName = (LPWSTR)ptr;
3942 ptr += size;
3943 left -= size;
3944 } else
3945 space = FALSE;
3946 *pcbNeeded += size;
3948 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3949 unicode)) {
3950 if(space && size <= left) {
3951 pi5->pPortName = (LPWSTR)ptr;
3952 ptr += size;
3953 left -= size;
3954 } else
3955 space = FALSE;
3956 *pcbNeeded += size;
3958 if(pi5) {
3959 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3960 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3961 "dnsTimeout");
3962 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3963 "txTimeout");
3966 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3967 memset(pi5, 0, sizeof(*pi5));
3969 return space;
3972 /*****************************************************************************
3973 * WINSPOOL_GetPrinter
3975 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3976 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3977 * just a collection of pointers to strings.
3979 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3980 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3982 LPCWSTR name;
3983 DWORD size, needed = 0;
3984 LPBYTE ptr = NULL;
3985 HKEY hkeyPrinter, hkeyPrinters;
3986 BOOL ret;
3988 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3990 if (!(name = get_opened_printer_name(hPrinter))) {
3991 SetLastError(ERROR_INVALID_HANDLE);
3992 return FALSE;
3995 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3996 ERROR_SUCCESS) {
3997 ERR("Can't create Printers key\n");
3998 return FALSE;
4000 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
4002 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4003 RegCloseKey(hkeyPrinters);
4004 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4005 return FALSE;
4008 switch(Level) {
4009 case 2:
4011 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4013 size = sizeof(PRINTER_INFO_2W);
4014 if(size <= cbBuf) {
4015 ptr = pPrinter + size;
4016 cbBuf -= size;
4017 memset(pPrinter, 0, size);
4018 } else {
4019 pi2 = NULL;
4020 cbBuf = 0;
4022 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
4023 unicode);
4024 needed += size;
4025 break;
4028 case 4:
4030 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4032 size = sizeof(PRINTER_INFO_4W);
4033 if(size <= cbBuf) {
4034 ptr = pPrinter + size;
4035 cbBuf -= size;
4036 memset(pPrinter, 0, size);
4037 } else {
4038 pi4 = NULL;
4039 cbBuf = 0;
4041 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
4042 unicode);
4043 needed += size;
4044 break;
4048 case 5:
4050 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4052 size = sizeof(PRINTER_INFO_5W);
4053 if(size <= cbBuf) {
4054 ptr = pPrinter + size;
4055 cbBuf -= size;
4056 memset(pPrinter, 0, size);
4057 } else {
4058 pi5 = NULL;
4059 cbBuf = 0;
4062 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
4063 unicode);
4064 needed += size;
4065 break;
4068 default:
4069 FIXME("Unimplemented level %d\n", Level);
4070 SetLastError(ERROR_INVALID_LEVEL);
4071 RegCloseKey(hkeyPrinters);
4072 RegCloseKey(hkeyPrinter);
4073 return FALSE;
4076 RegCloseKey(hkeyPrinter);
4077 RegCloseKey(hkeyPrinters);
4079 TRACE("returning %d needed = %d\n", ret, needed);
4080 if(pcbNeeded) *pcbNeeded = needed;
4081 if(!ret)
4082 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4083 return ret;
4086 /*****************************************************************************
4087 * GetPrinterW [WINSPOOL.@]
4089 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4090 DWORD cbBuf, LPDWORD pcbNeeded)
4092 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4093 TRUE);
4096 /*****************************************************************************
4097 * GetPrinterA [WINSPOOL.@]
4099 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4100 DWORD cbBuf, LPDWORD pcbNeeded)
4102 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4103 FALSE);
4106 /*****************************************************************************
4107 * WINSPOOL_EnumPrinters
4109 * Implementation of EnumPrintersA|W
4111 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
4112 DWORD dwLevel, LPBYTE lpbPrinters,
4113 DWORD cbBuf, LPDWORD lpdwNeeded,
4114 LPDWORD lpdwReturned, BOOL unicode)
4117 HKEY hkeyPrinters, hkeyPrinter;
4118 WCHAR PrinterName[255];
4119 DWORD needed = 0, number = 0;
4120 DWORD used, i, left;
4121 PBYTE pi, buf;
4123 if(lpbPrinters)
4124 memset(lpbPrinters, 0, cbBuf);
4125 if(lpdwReturned)
4126 *lpdwReturned = 0;
4127 if(lpdwNeeded)
4128 *lpdwNeeded = 0;
4130 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4131 if(dwType == PRINTER_ENUM_DEFAULT)
4132 return TRUE;
4134 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4135 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4136 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4137 if (!dwType) {
4138 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4139 *lpdwNeeded = 0;
4140 *lpdwReturned = 0;
4141 return TRUE;
4146 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4147 FIXME("dwType = %08x\n", dwType);
4148 SetLastError(ERROR_INVALID_FLAGS);
4149 return FALSE;
4152 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4153 ERROR_SUCCESS) {
4154 ERR("Can't create Printers key\n");
4155 return FALSE;
4158 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4159 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4160 RegCloseKey(hkeyPrinters);
4161 ERR("Can't query Printers key\n");
4162 return FALSE;
4164 TRACE("Found %d printers\n", number);
4166 switch(dwLevel) {
4167 case 1:
4168 used = number * sizeof(PRINTER_INFO_1W);
4169 break;
4170 case 2:
4171 used = number * sizeof(PRINTER_INFO_2W);
4172 break;
4173 case 4:
4174 used = number * sizeof(PRINTER_INFO_4W);
4175 break;
4176 case 5:
4177 used = number * sizeof(PRINTER_INFO_5W);
4178 break;
4180 default:
4181 SetLastError(ERROR_INVALID_LEVEL);
4182 RegCloseKey(hkeyPrinters);
4183 return FALSE;
4185 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4187 for(i = 0; i < number; i++) {
4188 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
4189 ERROR_SUCCESS) {
4190 ERR("Can't enum key number %d\n", i);
4191 RegCloseKey(hkeyPrinters);
4192 return FALSE;
4194 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4195 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4196 ERROR_SUCCESS) {
4197 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4198 RegCloseKey(hkeyPrinters);
4199 return FALSE;
4202 if(cbBuf > used) {
4203 buf = lpbPrinters + used;
4204 left = cbBuf - used;
4205 } else {
4206 buf = NULL;
4207 left = 0;
4210 switch(dwLevel) {
4211 case 1:
4212 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4213 left, &needed, unicode);
4214 used += needed;
4215 if(pi) pi += sizeof(PRINTER_INFO_1W);
4216 break;
4217 case 2:
4218 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4219 left, &needed, unicode);
4220 used += needed;
4221 if(pi) pi += sizeof(PRINTER_INFO_2W);
4222 break;
4223 case 4:
4224 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4225 left, &needed, unicode);
4226 used += needed;
4227 if(pi) pi += sizeof(PRINTER_INFO_4W);
4228 break;
4229 case 5:
4230 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4231 left, &needed, unicode);
4232 used += needed;
4233 if(pi) pi += sizeof(PRINTER_INFO_5W);
4234 break;
4235 default:
4236 ERR("Shouldn't be here!\n");
4237 RegCloseKey(hkeyPrinter);
4238 RegCloseKey(hkeyPrinters);
4239 return FALSE;
4241 RegCloseKey(hkeyPrinter);
4243 RegCloseKey(hkeyPrinters);
4245 if(lpdwNeeded)
4246 *lpdwNeeded = used;
4248 if(used > cbBuf) {
4249 if(lpbPrinters)
4250 memset(lpbPrinters, 0, cbBuf);
4251 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4252 return FALSE;
4254 if(lpdwReturned)
4255 *lpdwReturned = number;
4256 SetLastError(ERROR_SUCCESS);
4257 return TRUE;
4261 /******************************************************************
4262 * EnumPrintersW [WINSPOOL.@]
4264 * Enumerates the available printers, print servers and print
4265 * providers, depending on the specified flags, name and level.
4267 * RETURNS:
4269 * If level is set to 1:
4270 * Returns an array of PRINTER_INFO_1 data structures in the
4271 * lpbPrinters buffer.
4273 * If level is set to 2:
4274 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4275 * Returns an array of PRINTER_INFO_2 data structures in the
4276 * lpbPrinters buffer. Note that according to MSDN also an
4277 * OpenPrinter should be performed on every remote printer.
4279 * If level is set to 4 (officially WinNT only):
4280 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4281 * Fast: Only the registry is queried to retrieve printer names,
4282 * no connection to the driver is made.
4283 * Returns an array of PRINTER_INFO_4 data structures in the
4284 * lpbPrinters buffer.
4286 * If level is set to 5 (officially WinNT4/Win9x only):
4287 * Fast: Only the registry is queried to retrieve printer names,
4288 * no connection to the driver is made.
4289 * Returns an array of PRINTER_INFO_5 data structures in the
4290 * lpbPrinters buffer.
4292 * If level set to 3 or 6+:
4293 * returns zero (failure!)
4295 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4296 * for information.
4298 * BUGS:
4299 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4300 * - Only levels 2, 4 and 5 are implemented at the moment.
4301 * - 16-bit printer drivers are not enumerated.
4302 * - Returned amount of bytes used/needed does not match the real Windoze
4303 * implementation (as in this implementation, all strings are part
4304 * of the buffer, whereas Win32 keeps them somewhere else)
4305 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4307 * NOTE:
4308 * - In a regular Wine installation, no registry settings for printers
4309 * exist, which makes this function return an empty list.
4311 BOOL WINAPI EnumPrintersW(
4312 DWORD dwType, /* [in] Types of print objects to enumerate */
4313 LPWSTR lpszName, /* [in] name of objects to enumerate */
4314 DWORD dwLevel, /* [in] type of printer info structure */
4315 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4316 DWORD cbBuf, /* [in] max size of buffer in bytes */
4317 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4318 LPDWORD lpdwReturned /* [out] number of entries returned */
4321 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4322 lpdwNeeded, lpdwReturned, TRUE);
4325 /******************************************************************
4326 * EnumPrintersA [WINSPOOL.@]
4329 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
4330 DWORD dwLevel, LPBYTE lpbPrinters,
4331 DWORD cbBuf, LPDWORD lpdwNeeded,
4332 LPDWORD lpdwReturned)
4334 BOOL ret, unicode = FALSE;
4335 UNICODE_STRING lpszNameW;
4336 PWSTR pwstrNameW;
4338 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
4339 if(!cbBuf) unicode = TRUE; /* return a buffer that's big enough for the unicode version */
4340 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
4341 lpdwNeeded, lpdwReturned, unicode);
4342 RtlFreeUnicodeString(&lpszNameW);
4343 return ret;
4346 /*****************************************************************************
4347 * WINSPOOL_GetDriverInfoFromReg [internal]
4349 * Enters the information from the registry into the DRIVER_INFO struct
4351 * RETURNS
4352 * zero if the printer driver does not exist in the registry
4353 * (only if Level > 1) otherwise nonzero
4355 static BOOL WINSPOOL_GetDriverInfoFromReg(
4356 HKEY hkeyDrivers,
4357 LPWSTR DriverName,
4358 const printenv_t * env,
4359 DWORD Level,
4360 LPBYTE ptr, /* DRIVER_INFO */
4361 LPBYTE pDriverStrings, /* strings buffer */
4362 DWORD cbBuf, /* size of string buffer */
4363 LPDWORD pcbNeeded, /* space needed for str. */
4364 BOOL unicode) /* type of strings */
4366 DWORD size, tmp;
4367 HKEY hkeyDriver;
4368 WCHAR driverdir[MAX_PATH];
4369 DWORD dirlen;
4370 LPBYTE strPtr = pDriverStrings;
4371 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4373 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers,
4374 debugstr_w(DriverName), env,
4375 Level, di, pDriverStrings, cbBuf, unicode);
4377 if (di) ZeroMemory(di, di_sizeof[Level]);
4379 if (unicode) {
4380 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4381 if (*pcbNeeded <= cbBuf)
4382 strcpyW((LPWSTR)strPtr, DriverName);
4384 else
4386 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL, NULL);
4387 if (*pcbNeeded <= cbBuf)
4388 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4391 /* pName for level 1 has a different offset! */
4392 if (Level == 1) {
4393 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4394 return TRUE;
4397 /* .cVersion and .pName for level > 1 */
4398 if (di) {
4399 di->cVersion = env->driverversion;
4400 di->pName = (LPWSTR) strPtr;
4401 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4404 /* Reserve Space for the largest subdir and a Backslash*/
4405 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4406 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4407 /* Should never Fail */
4408 return FALSE;
4410 lstrcatW(driverdir, env->versionsubdir);
4411 lstrcatW(driverdir, backslashW);
4413 /* dirlen must not include the terminating zero */
4414 dirlen = (unicode) ? lstrlenW(driverdir) * sizeof(WCHAR) :
4415 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, NULL, 0, NULL, NULL) -1;
4417 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4418 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4419 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4420 return FALSE;
4423 /* pEnvironment */
4424 if (unicode)
4425 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4426 else
4427 size = WideCharToMultiByte(CP_ACP, 0, env->envname, -1, NULL, 0, NULL, NULL);
4429 *pcbNeeded += size;
4430 if (*pcbNeeded <= cbBuf) {
4431 if (unicode) {
4432 lstrcpyW((LPWSTR)strPtr, env->envname);
4434 else
4436 WideCharToMultiByte(CP_ACP, 0, env->envname, -1, (LPSTR)strPtr, size, NULL, NULL);
4438 if (di) di->pEnvironment = (LPWSTR)strPtr;
4439 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4442 /* .pDriverPath is the Graphics rendering engine.
4443 The full Path is required to avoid a crash in some apps */
4444 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size, unicode)) {
4445 *pcbNeeded += size;
4446 if (*pcbNeeded <= cbBuf)
4447 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp, unicode);
4449 if (di) di->pDriverPath = (LPWSTR)strPtr;
4450 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4453 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4454 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size, unicode)) {
4455 *pcbNeeded += size;
4456 if (*pcbNeeded <= cbBuf)
4457 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size, unicode);
4459 if (di) di->pDataFile = (LPWSTR)strPtr;
4460 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4463 /* .pConfigFile is the Driver user Interface */
4464 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size, unicode)) {
4465 *pcbNeeded += size;
4466 if (*pcbNeeded <= cbBuf)
4467 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size, unicode);
4469 if (di) di->pConfigFile = (LPWSTR)strPtr;
4470 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4473 if (Level == 2 ) {
4474 RegCloseKey(hkeyDriver);
4475 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4476 return TRUE;
4479 if (Level == 5 ) {
4480 RegCloseKey(hkeyDriver);
4481 FIXME("level 5: incomplete\n");
4482 return TRUE;
4485 /* .pHelpFile */
4486 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size, unicode)) {
4487 *pcbNeeded += size;
4488 if (*pcbNeeded <= cbBuf)
4489 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size, unicode);
4491 if (di) di->pHelpFile = (LPWSTR)strPtr;
4492 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4495 /* .pDependentFiles */
4496 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size, unicode)) {
4497 *pcbNeeded += size;
4498 if (*pcbNeeded <= cbBuf)
4499 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size, unicode);
4501 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4502 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4505 /* .pMonitorName is the optional Language Monitor */
4506 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size, unicode)) {
4507 *pcbNeeded += size;
4508 if (*pcbNeeded <= cbBuf)
4509 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size, unicode);
4511 if (di) di->pMonitorName = (LPWSTR)strPtr;
4512 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4515 /* .pDefaultDataType */
4516 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size, unicode)) {
4517 *pcbNeeded += size;
4518 if(*pcbNeeded <= cbBuf)
4519 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size, unicode);
4521 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4522 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4525 if (Level == 3 ) {
4526 RegCloseKey(hkeyDriver);
4527 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4528 return TRUE;
4531 /* .pszzPreviousNames */
4532 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size, unicode)) {
4533 *pcbNeeded += size;
4534 if(*pcbNeeded <= cbBuf)
4535 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size, unicode);
4537 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4538 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4541 if (Level == 4 ) {
4542 RegCloseKey(hkeyDriver);
4543 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4544 return TRUE;
4547 /* support is missing, but not important enough for a FIXME */
4548 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4550 /* .pszMfgName */
4551 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size, unicode)) {
4552 *pcbNeeded += size;
4553 if(*pcbNeeded <= cbBuf)
4554 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size, unicode);
4556 if (di) di->pszMfgName = (LPWSTR)strPtr;
4557 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4560 /* .pszOEMUrl */
4561 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size, unicode)) {
4562 *pcbNeeded += size;
4563 if(*pcbNeeded <= cbBuf)
4564 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size, unicode);
4566 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4567 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4570 /* .pszHardwareID */
4571 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size, unicode)) {
4572 *pcbNeeded += size;
4573 if(*pcbNeeded <= cbBuf)
4574 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size, unicode);
4576 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4577 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4580 /* .pszProvider */
4581 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size, unicode)) {
4582 *pcbNeeded += size;
4583 if(*pcbNeeded <= cbBuf)
4584 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size, unicode);
4586 if (di) di->pszProvider = (LPWSTR)strPtr;
4587 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4590 if (Level == 6 ) {
4591 RegCloseKey(hkeyDriver);
4592 return TRUE;
4595 /* support is missing, but not important enough for a FIXME */
4596 TRACE("level 8: incomplete\n");
4598 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4599 RegCloseKey(hkeyDriver);
4600 return TRUE;
4603 /*****************************************************************************
4604 * WINSPOOL_GetPrinterDriver
4606 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
4607 DWORD Level, LPBYTE pDriverInfo,
4608 DWORD cbBuf, LPDWORD pcbNeeded,
4609 BOOL unicode)
4611 LPCWSTR name;
4612 WCHAR DriverName[100];
4613 DWORD ret, type, size, needed = 0;
4614 LPBYTE ptr = NULL;
4615 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4616 const printenv_t * env;
4618 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4619 Level,pDriverInfo,cbBuf, pcbNeeded);
4622 if (!(name = get_opened_printer_name(hPrinter))) {
4623 SetLastError(ERROR_INVALID_HANDLE);
4624 return FALSE;
4627 if (Level < 1 || Level == 7 || Level > 8) {
4628 SetLastError(ERROR_INVALID_LEVEL);
4629 return FALSE;
4632 env = validate_envW(pEnvironment);
4633 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4635 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4636 ERROR_SUCCESS) {
4637 ERR("Can't create Printers key\n");
4638 return FALSE;
4640 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4641 != ERROR_SUCCESS) {
4642 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4643 RegCloseKey(hkeyPrinters);
4644 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4645 return FALSE;
4647 size = sizeof(DriverName);
4648 DriverName[0] = 0;
4649 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4650 (LPBYTE)DriverName, &size);
4651 RegCloseKey(hkeyPrinter);
4652 RegCloseKey(hkeyPrinters);
4653 if(ret != ERROR_SUCCESS) {
4654 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4655 return FALSE;
4658 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4659 if(!hkeyDrivers) {
4660 ERR("Can't create Drivers key\n");
4661 return FALSE;
4664 size = di_sizeof[Level];
4665 if ((size <= cbBuf) && pDriverInfo)
4666 ptr = pDriverInfo + size;
4668 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4669 env, Level, pDriverInfo, ptr,
4670 (cbBuf < size) ? 0 : cbBuf - size,
4671 &needed, unicode)) {
4672 RegCloseKey(hkeyDrivers);
4673 return FALSE;
4676 RegCloseKey(hkeyDrivers);
4678 if(pcbNeeded) *pcbNeeded = size + needed;
4679 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4680 if(cbBuf >= needed) return TRUE;
4681 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4682 return FALSE;
4685 /*****************************************************************************
4686 * GetPrinterDriverA [WINSPOOL.@]
4688 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4689 DWORD Level, LPBYTE pDriverInfo,
4690 DWORD cbBuf, LPDWORD pcbNeeded)
4692 BOOL ret;
4693 UNICODE_STRING pEnvW;
4694 PWSTR pwstrEnvW;
4696 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4697 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4698 cbBuf, pcbNeeded, FALSE);
4699 RtlFreeUnicodeString(&pEnvW);
4700 return ret;
4702 /*****************************************************************************
4703 * GetPrinterDriverW [WINSPOOL.@]
4705 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4706 DWORD Level, LPBYTE pDriverInfo,
4707 DWORD cbBuf, LPDWORD pcbNeeded)
4709 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4710 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4713 /*****************************************************************************
4714 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4716 * Return the PATH for the Printer-Drivers (UNICODE)
4718 * PARAMS
4719 * pName [I] Servername (NT only) or NULL (local Computer)
4720 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4721 * Level [I] Structure-Level (must be 1)
4722 * pDriverDirectory [O] PTR to Buffer that receives the Result
4723 * cbBuf [I] Size of Buffer at pDriverDirectory
4724 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4725 * required for pDriverDirectory
4727 * RETURNS
4728 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4729 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4730 * if cbBuf is too small
4732 * Native Values returned in pDriverDirectory on Success:
4733 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4734 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4735 *| win9x(Windows 4.0): "%winsysdir%"
4737 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4739 * FIXME
4740 *- Only NULL or "" is supported for pName
4743 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4744 DWORD Level, LPBYTE pDriverDirectory,
4745 DWORD cbBuf, LPDWORD pcbNeeded)
4747 DWORD needed;
4748 const printenv_t * env;
4750 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4751 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4752 if(pName != NULL && pName[0]) {
4753 FIXME("pName unsupported: %s\n", debugstr_w(pName));
4754 SetLastError(ERROR_INVALID_PARAMETER);
4755 return FALSE;
4758 env = validate_envW(pEnvironment);
4759 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
4761 if(Level != 1) {
4762 WARN("(Level: %d) is ignored in win9x\n", Level);
4763 SetLastError(ERROR_INVALID_LEVEL);
4764 return FALSE;
4767 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
4768 needed = GetSystemDirectoryW(NULL, 0);
4769 /* add the Size for the Subdirectories */
4770 needed += lstrlenW(spooldriversW);
4771 needed += lstrlenW(env->subdir);
4772 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
4774 if(pcbNeeded)
4775 *pcbNeeded = needed;
4776 TRACE("required: 0x%x/%d\n", needed, needed);
4777 if(needed > cbBuf) {
4778 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4779 return FALSE;
4781 if(pcbNeeded == NULL) {
4782 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
4783 SetLastError(RPC_X_NULL_REF_POINTER);
4784 return FALSE;
4786 if(pDriverDirectory == NULL) {
4787 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
4788 SetLastError(ERROR_INVALID_USER_BUFFER);
4789 return FALSE;
4792 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
4793 /* add the Subdirectories */
4794 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
4795 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
4796 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
4797 return TRUE;
4801 /*****************************************************************************
4802 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4804 * Return the PATH for the Printer-Drivers (ANSI)
4806 * See GetPrinterDriverDirectoryW.
4808 * NOTES
4809 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4812 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4813 DWORD Level, LPBYTE pDriverDirectory,
4814 DWORD cbBuf, LPDWORD pcbNeeded)
4816 UNICODE_STRING nameW, environmentW;
4817 BOOL ret;
4818 DWORD pcbNeededW;
4819 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4820 WCHAR *driverDirectoryW = NULL;
4822 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4823 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4825 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4827 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4828 else nameW.Buffer = NULL;
4829 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4830 else environmentW.Buffer = NULL;
4832 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4833 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4834 if (ret) {
4835 DWORD needed;
4836 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4837 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4838 if(pcbNeeded)
4839 *pcbNeeded = needed;
4840 ret = (needed <= cbBuf) ? TRUE : FALSE;
4841 } else
4842 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4844 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4846 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4847 RtlFreeUnicodeString(&environmentW);
4848 RtlFreeUnicodeString(&nameW);
4850 return ret;
4853 /*****************************************************************************
4854 * AddPrinterDriverA [WINSPOOL.@]
4856 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4858 DRIVER_INFO_3A di3;
4859 HKEY hkeyDrivers, hkeyName;
4860 static CHAR empty[] = "",
4861 nullnull[] = "\0";
4863 TRACE("(%s,%d,%p)\n",debugstr_a(pName),level,pDriverInfo);
4865 if(level != 2 && level != 3) {
4866 SetLastError(ERROR_INVALID_LEVEL);
4867 return FALSE;
4869 if ((pName) && (pName[0])) {
4870 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
4871 SetLastError(ERROR_INVALID_PARAMETER);
4872 return FALSE;
4874 if(!pDriverInfo) {
4875 WARN("pDriverInfo == NULL\n");
4876 SetLastError(ERROR_INVALID_PARAMETER);
4877 return FALSE;
4880 if(level == 3)
4881 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
4882 else {
4883 memset(&di3, 0, sizeof(di3));
4884 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
4887 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
4888 !di3.pDataFile) {
4889 SetLastError(ERROR_INVALID_PARAMETER);
4890 return FALSE;
4893 if(!di3.pDefaultDataType) di3.pDefaultDataType = empty;
4894 if(!di3.pDependentFiles) di3.pDependentFiles = nullnull;
4895 if(!di3.pHelpFile) di3.pHelpFile = empty;
4896 if(!di3.pMonitorName) di3.pMonitorName = empty;
4898 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
4900 if(!hkeyDrivers) {
4901 ERR("Can't create Drivers key\n");
4902 return FALSE;
4905 if(level == 2) { /* apparently can't overwrite with level2 */
4906 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
4907 RegCloseKey(hkeyName);
4908 RegCloseKey(hkeyDrivers);
4909 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
4910 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
4911 return FALSE;
4914 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
4915 RegCloseKey(hkeyDrivers);
4916 ERR("Can't create Name key\n");
4917 return FALSE;
4919 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
4920 lstrlenA(di3.pConfigFile) + 1);
4921 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, lstrlenA(di3.pDataFile) + 1);
4922 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, lstrlenA(di3.pDriverPath) + 1);
4923 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
4924 sizeof(DWORD));
4925 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, lstrlenA(di3.pDefaultDataType));
4926 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
4927 (LPBYTE) di3.pDependentFiles, multi_sz_lenA(di3.pDependentFiles));
4928 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, lstrlenA(di3.pHelpFile) + 1);
4929 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, lstrlenA(di3.pMonitorName) + 1);
4930 RegCloseKey(hkeyName);
4931 RegCloseKey(hkeyDrivers);
4933 return TRUE;
4936 /*****************************************************************************
4937 * AddPrinterDriverW [WINSPOOL.@]
4939 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
4940 LPBYTE pDriverInfo)
4942 FIXME("(%s,%d,%p): stub\n",debugstr_w(printerName),
4943 level,pDriverInfo);
4944 return FALSE;
4947 /*****************************************************************************
4948 * AddPrintProcessorA [WINSPOOL.@]
4950 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4951 LPSTR pPrintProcessorName)
4953 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4954 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4955 return FALSE;
4958 /*****************************************************************************
4959 * AddPrintProcessorW [WINSPOOL.@]
4961 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4962 LPWSTR pPrintProcessorName)
4964 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4965 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4966 return FALSE;
4969 /*****************************************************************************
4970 * AddPrintProvidorA [WINSPOOL.@]
4972 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4974 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4975 return FALSE;
4978 /*****************************************************************************
4979 * AddPrintProvidorW [WINSPOOL.@]
4981 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4983 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4984 return FALSE;
4987 /*****************************************************************************
4988 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4990 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4991 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4993 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4994 pDevModeOutput, pDevModeInput);
4995 return 0;
4998 /*****************************************************************************
4999 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5001 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5002 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5004 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5005 pDevModeOutput, pDevModeInput);
5006 return 0;
5009 /*****************************************************************************
5010 * PrinterProperties [WINSPOOL.@]
5012 * Displays a dialog to set the properties of the printer.
5014 * RETURNS
5015 * nonzero on success or zero on failure
5017 * BUGS
5018 * implemented as stub only
5020 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5021 HANDLE hPrinter /* [in] handle to printer object */
5023 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5024 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5025 return FALSE;
5028 /*****************************************************************************
5029 * EnumJobsA [WINSPOOL.@]
5032 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5033 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5034 LPDWORD pcReturned)
5036 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5037 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5039 if(pcbNeeded) *pcbNeeded = 0;
5040 if(pcReturned) *pcReturned = 0;
5041 return FALSE;
5045 /*****************************************************************************
5046 * EnumJobsW [WINSPOOL.@]
5049 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5050 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5051 LPDWORD pcReturned)
5053 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5054 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5056 if(pcbNeeded) *pcbNeeded = 0;
5057 if(pcReturned) *pcReturned = 0;
5058 return FALSE;
5061 /*****************************************************************************
5062 * WINSPOOL_EnumPrinterDrivers [internal]
5064 * Delivers information about all printer drivers installed on the
5065 * localhost or a given server
5067 * RETURNS
5068 * nonzero on success or zero on failure. If the buffer for the returned
5069 * information is too small the function will return an error
5071 * BUGS
5072 * - only implemented for localhost, foreign hosts will return an error
5074 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5075 DWORD Level, LPBYTE pDriverInfo,
5076 DWORD cbBuf, LPDWORD pcbNeeded,
5077 LPDWORD pcReturned, BOOL unicode)
5079 { HKEY hkeyDrivers;
5080 DWORD i, needed, number = 0, size = 0;
5081 WCHAR DriverNameW[255];
5082 PBYTE ptr;
5083 const printenv_t * env;
5085 TRACE("%s,%s,%d,%p,%d,%d\n",
5086 debugstr_w(pName), debugstr_w(pEnvironment),
5087 Level, pDriverInfo, cbBuf, unicode);
5089 /* check for local drivers */
5090 if((pName) && (pName[0])) {
5091 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5092 SetLastError(ERROR_ACCESS_DENIED);
5093 return FALSE;
5096 env = validate_envW(pEnvironment);
5097 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5099 /* check input parameter */
5100 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5101 SetLastError(ERROR_INVALID_LEVEL);
5102 return FALSE;
5105 /* initialize return values */
5106 if(pDriverInfo)
5107 memset( pDriverInfo, 0, cbBuf);
5108 *pcbNeeded = 0;
5109 *pcReturned = 0;
5111 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
5112 if(!hkeyDrivers) {
5113 ERR("Can't open Drivers key\n");
5114 return FALSE;
5117 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
5118 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5119 RegCloseKey(hkeyDrivers);
5120 ERR("Can't query Drivers key\n");
5121 return FALSE;
5123 TRACE("Found %d Drivers\n", number);
5125 /* get size of single struct
5126 * unicode and ascii structure have the same size
5128 size = di_sizeof[Level];
5130 /* calculate required buffer size */
5131 *pcbNeeded = size * number;
5133 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
5134 i < number;
5135 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
5136 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
5137 != ERROR_SUCCESS) {
5138 ERR("Can't enum key number %d\n", i);
5139 RegCloseKey(hkeyDrivers);
5140 return FALSE;
5142 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5143 env, Level, ptr,
5144 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
5145 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5146 &needed, unicode)) {
5147 RegCloseKey(hkeyDrivers);
5148 return FALSE;
5150 (*pcbNeeded) += needed;
5153 RegCloseKey(hkeyDrivers);
5155 if(cbBuf < *pcbNeeded){
5156 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5157 return FALSE;
5160 *pcReturned = number;
5161 return TRUE;
5164 /*****************************************************************************
5165 * EnumPrinterDriversW [WINSPOOL.@]
5167 * see function EnumPrinterDrivers for RETURNS, BUGS
5169 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5170 LPBYTE pDriverInfo, DWORD cbBuf,
5171 LPDWORD pcbNeeded, LPDWORD pcReturned)
5173 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5174 cbBuf, pcbNeeded, pcReturned, TRUE);
5177 /*****************************************************************************
5178 * EnumPrinterDriversA [WINSPOOL.@]
5180 * see function EnumPrinterDrivers for RETURNS, BUGS
5182 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5183 LPBYTE pDriverInfo, DWORD cbBuf,
5184 LPDWORD pcbNeeded, LPDWORD pcReturned)
5185 { BOOL ret;
5186 UNICODE_STRING pNameW, pEnvironmentW;
5187 PWSTR pwstrNameW, pwstrEnvironmentW;
5189 pwstrNameW = asciitounicode(&pNameW, pName);
5190 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5192 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5193 Level, pDriverInfo, cbBuf, pcbNeeded,
5194 pcReturned, FALSE);
5195 RtlFreeUnicodeString(&pNameW);
5196 RtlFreeUnicodeString(&pEnvironmentW);
5198 return ret;
5201 /******************************************************************************
5202 * EnumPortsA (WINSPOOL.@)
5204 * See EnumPortsW.
5207 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5208 LPDWORD pcbNeeded, LPDWORD pcReturned)
5210 BOOL res;
5211 LPBYTE bufferW = NULL;
5212 LPWSTR nameW = NULL;
5213 DWORD needed = 0;
5214 DWORD numentries = 0;
5215 INT len;
5217 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5218 cbBuf, pcbNeeded, pcReturned);
5220 /* convert servername to unicode */
5221 if (pName) {
5222 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5223 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5224 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5226 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5227 needed = cbBuf * sizeof(WCHAR);
5228 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5229 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5231 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5232 if (pcbNeeded) needed = *pcbNeeded;
5233 /* HeapReAlloc return NULL, when bufferW was NULL */
5234 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5235 HeapAlloc(GetProcessHeap(), 0, needed);
5237 /* Try again with the large Buffer */
5238 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5240 needed = pcbNeeded ? *pcbNeeded : 0;
5241 numentries = pcReturned ? *pcReturned : 0;
5244 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5245 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5247 if (res) {
5248 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5249 DWORD entrysize = 0;
5250 DWORD index;
5251 LPSTR ptr;
5252 LPPORT_INFO_2W pi2w;
5253 LPPORT_INFO_2A pi2a;
5255 needed = 0;
5256 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5258 /* First pass: calculate the size for all Entries */
5259 pi2w = (LPPORT_INFO_2W) bufferW;
5260 pi2a = (LPPORT_INFO_2A) pPorts;
5261 index = 0;
5262 while (index < numentries) {
5263 index++;
5264 needed += entrysize; /* PORT_INFO_?A */
5265 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5267 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5268 NULL, 0, NULL, NULL);
5269 if (Level > 1) {
5270 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5271 NULL, 0, NULL, NULL);
5272 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5273 NULL, 0, NULL, NULL);
5275 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5276 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5277 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5280 /* check for errors and quit on failure */
5281 if (cbBuf < needed) {
5282 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5283 res = FALSE;
5284 goto cleanup;
5286 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5287 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5288 cbBuf -= len ; /* free Bytes in the user-Buffer */
5289 pi2w = (LPPORT_INFO_2W) bufferW;
5290 pi2a = (LPPORT_INFO_2A) pPorts;
5291 index = 0;
5292 /* Second Pass: Fill the User Buffer (if we have one) */
5293 while ((index < numentries) && pPorts) {
5294 index++;
5295 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5296 pi2a->pPortName = ptr;
5297 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5298 ptr, cbBuf , NULL, NULL);
5299 ptr += len;
5300 cbBuf -= len;
5301 if (Level > 1) {
5302 pi2a->pMonitorName = ptr;
5303 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5304 ptr, cbBuf, NULL, NULL);
5305 ptr += len;
5306 cbBuf -= len;
5308 pi2a->pDescription = ptr;
5309 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5310 ptr, cbBuf, NULL, NULL);
5311 ptr += len;
5312 cbBuf -= len;
5314 pi2a->fPortType = pi2w->fPortType;
5315 pi2a->Reserved = 0; /* documented: "must be zero" */
5318 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5319 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5320 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5324 cleanup:
5325 if (pcbNeeded) *pcbNeeded = needed;
5326 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5328 HeapFree(GetProcessHeap(), 0, nameW);
5329 HeapFree(GetProcessHeap(), 0, bufferW);
5331 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5332 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5334 return (res);
5338 /******************************************************************************
5339 * EnumPortsW (WINSPOOL.@)
5341 * Enumerate available Ports
5343 * PARAMS
5344 * name [I] Servername or NULL (local Computer)
5345 * level [I] Structure-Level (1 or 2)
5346 * buffer [O] PTR to Buffer that receives the Result
5347 * bufsize [I] Size of Buffer at buffer
5348 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5349 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5351 * RETURNS
5352 * Success: TRUE
5353 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5357 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5359 DWORD needed = 0;
5360 DWORD numentries = 0;
5361 BOOL res = FALSE;
5363 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5364 cbBuf, pcbNeeded, pcReturned);
5366 if (pName && (pName[0])) {
5367 FIXME("not implemented for Server %s\n", debugstr_w(pName));
5368 SetLastError(ERROR_ACCESS_DENIED);
5369 goto emP_cleanup;
5372 /* Level is not checked in win9x */
5373 if (!Level || (Level > 2)) {
5374 WARN("level (%d) is ignored in win9x\n", Level);
5375 SetLastError(ERROR_INVALID_LEVEL);
5376 goto emP_cleanup;
5378 if (!pcbNeeded) {
5379 SetLastError(RPC_X_NULL_REF_POINTER);
5380 goto emP_cleanup;
5383 EnterCriticalSection(&monitor_handles_cs);
5384 monitor_loadall();
5386 /* Scan all local Ports */
5387 numentries = 0;
5388 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
5390 /* we calculated the needed buffersize. now do the error-checks */
5391 if (cbBuf < needed) {
5392 monitor_unloadall();
5393 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5394 goto emP_cleanup_cs;
5396 else if (!pPorts || !pcReturned) {
5397 monitor_unloadall();
5398 SetLastError(RPC_X_NULL_REF_POINTER);
5399 goto emP_cleanup_cs;
5402 /* Fill the Buffer */
5403 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
5404 res = TRUE;
5405 monitor_unloadall();
5407 emP_cleanup_cs:
5408 LeaveCriticalSection(&monitor_handles_cs);
5410 emP_cleanup:
5411 if (pcbNeeded) *pcbNeeded = needed;
5412 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5414 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5415 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5417 return (res);
5420 /******************************************************************************
5421 * GetDefaultPrinterW (WINSPOOL.@)
5423 * FIXME
5424 * This function must read the value from data 'device' of key
5425 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5427 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5429 BOOL retval = TRUE;
5430 DWORD insize, len;
5431 WCHAR *buffer, *ptr;
5433 if (!namesize)
5435 SetLastError(ERROR_INVALID_PARAMETER);
5436 return FALSE;
5439 /* make the buffer big enough for the stuff from the profile/registry,
5440 * the content must fit into the local buffer to compute the correct
5441 * size even if the extern buffer is too small or not given.
5442 * (20 for ,driver,port) */
5443 insize = *namesize;
5444 len = max(100, (insize + 20));
5445 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5447 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5449 SetLastError (ERROR_FILE_NOT_FOUND);
5450 retval = FALSE;
5451 goto end;
5453 TRACE("%s\n", debugstr_w(buffer));
5455 if ((ptr = strchrW(buffer, ',')) == NULL)
5457 SetLastError(ERROR_INVALID_NAME);
5458 retval = FALSE;
5459 goto end;
5462 *ptr = 0;
5463 *namesize = strlenW(buffer) + 1;
5464 if(!name || (*namesize > insize))
5466 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5467 retval = FALSE;
5468 goto end;
5470 strcpyW(name, buffer);
5472 end:
5473 HeapFree( GetProcessHeap(), 0, buffer);
5474 return retval;
5478 /******************************************************************************
5479 * GetDefaultPrinterA (WINSPOOL.@)
5481 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5483 BOOL retval = TRUE;
5484 DWORD insize = 0;
5485 WCHAR *bufferW = NULL;
5487 if (!namesize)
5489 SetLastError(ERROR_INVALID_PARAMETER);
5490 return FALSE;
5493 if(name && *namesize) {
5494 insize = *namesize;
5495 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5498 if(!GetDefaultPrinterW( bufferW, namesize)) {
5499 retval = FALSE;
5500 goto end;
5503 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5504 NULL, NULL);
5505 if (!*namesize)
5507 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5508 retval = FALSE;
5510 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5512 end:
5513 HeapFree( GetProcessHeap(), 0, bufferW);
5514 return retval;
5518 /******************************************************************************
5519 * SetDefaultPrinterW (WINSPOOL.204)
5521 * Set the Name of the Default Printer
5523 * PARAMS
5524 * pszPrinter [I] Name of the Printer or NULL
5526 * RETURNS
5527 * Success: True
5528 * Failure: FALSE
5530 * NOTES
5531 * When the Parameter is NULL or points to an Empty String and
5532 * a Default Printer was already present, then this Function changes nothing.
5533 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5534 * the First enumerated local Printer is used.
5537 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5540 TRACE("(%s)\n", debugstr_w(pszPrinter));
5542 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5543 return FALSE;
5546 /******************************************************************************
5547 * SetDefaultPrinterA (WINSPOOL.202)
5549 * See SetDefaultPrinterW.
5552 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5555 TRACE("(%s)\n", debugstr_a(pszPrinter));
5557 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5558 return FALSE;
5562 /******************************************************************************
5563 * SetPrinterDataExA (WINSPOOL.@)
5565 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5566 LPCSTR pValueName, DWORD Type,
5567 LPBYTE pData, DWORD cbData)
5569 HKEY hkeyPrinter, hkeySubkey;
5570 DWORD ret;
5572 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5573 debugstr_a(pValueName), Type, pData, cbData);
5575 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5576 != ERROR_SUCCESS)
5577 return ret;
5579 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5580 != ERROR_SUCCESS) {
5581 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5582 RegCloseKey(hkeyPrinter);
5583 return ret;
5585 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5586 RegCloseKey(hkeySubkey);
5587 RegCloseKey(hkeyPrinter);
5588 return ret;
5591 /******************************************************************************
5592 * SetPrinterDataExW (WINSPOOL.@)
5594 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5595 LPCWSTR pValueName, DWORD Type,
5596 LPBYTE pData, DWORD cbData)
5598 HKEY hkeyPrinter, hkeySubkey;
5599 DWORD ret;
5601 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5602 debugstr_w(pValueName), Type, pData, cbData);
5604 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5605 != ERROR_SUCCESS)
5606 return ret;
5608 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5609 != ERROR_SUCCESS) {
5610 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5611 RegCloseKey(hkeyPrinter);
5612 return ret;
5614 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5615 RegCloseKey(hkeySubkey);
5616 RegCloseKey(hkeyPrinter);
5617 return ret;
5620 /******************************************************************************
5621 * SetPrinterDataA (WINSPOOL.@)
5623 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5624 LPBYTE pData, DWORD cbData)
5626 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5627 pData, cbData);
5630 /******************************************************************************
5631 * SetPrinterDataW (WINSPOOL.@)
5633 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5634 LPBYTE pData, DWORD cbData)
5636 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5637 pData, cbData);
5640 /******************************************************************************
5641 * GetPrinterDataExA (WINSPOOL.@)
5643 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5644 LPCSTR pValueName, LPDWORD pType,
5645 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5647 HKEY hkeyPrinter, hkeySubkey;
5648 DWORD ret;
5650 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5651 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5652 pcbNeeded);
5654 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5655 != ERROR_SUCCESS)
5656 return ret;
5658 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5659 != ERROR_SUCCESS) {
5660 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5661 RegCloseKey(hkeyPrinter);
5662 return ret;
5664 *pcbNeeded = nSize;
5665 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5666 RegCloseKey(hkeySubkey);
5667 RegCloseKey(hkeyPrinter);
5668 return ret;
5671 /******************************************************************************
5672 * GetPrinterDataExW (WINSPOOL.@)
5674 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5675 LPCWSTR pValueName, LPDWORD pType,
5676 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5678 HKEY hkeyPrinter, hkeySubkey;
5679 DWORD ret;
5681 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5682 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5683 pcbNeeded);
5685 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5686 != ERROR_SUCCESS)
5687 return ret;
5689 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5690 != ERROR_SUCCESS) {
5691 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5692 RegCloseKey(hkeyPrinter);
5693 return ret;
5695 *pcbNeeded = nSize;
5696 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5697 RegCloseKey(hkeySubkey);
5698 RegCloseKey(hkeyPrinter);
5699 return ret;
5702 /******************************************************************************
5703 * GetPrinterDataA (WINSPOOL.@)
5705 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5706 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5708 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5709 pData, nSize, pcbNeeded);
5712 /******************************************************************************
5713 * GetPrinterDataW (WINSPOOL.@)
5715 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5716 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5718 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5719 pData, nSize, pcbNeeded);
5722 /*******************************************************************************
5723 * EnumPrinterDataExW [WINSPOOL.@]
5725 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5726 LPBYTE pEnumValues, DWORD cbEnumValues,
5727 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5729 HKEY hkPrinter, hkSubKey;
5730 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5731 cbValueNameLen, cbMaxValueLen, cbValueLen,
5732 cbBufSize, dwType;
5733 LPWSTR lpValueName;
5734 HANDLE hHeap;
5735 PBYTE lpValue;
5736 PPRINTER_ENUM_VALUESW ppev;
5738 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5740 if (pKeyName == NULL || *pKeyName == 0)
5741 return ERROR_INVALID_PARAMETER;
5743 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5744 if (ret != ERROR_SUCCESS)
5746 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5747 hPrinter, ret);
5748 return ret;
5751 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5752 if (ret != ERROR_SUCCESS)
5754 r = RegCloseKey (hkPrinter);
5755 if (r != ERROR_SUCCESS)
5756 WARN ("RegCloseKey returned %i\n", r);
5757 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5758 debugstr_w (pKeyName), ret);
5759 return ret;
5762 ret = RegCloseKey (hkPrinter);
5763 if (ret != ERROR_SUCCESS)
5765 ERR ("RegCloseKey returned %i\n", ret);
5766 r = RegCloseKey (hkSubKey);
5767 if (r != ERROR_SUCCESS)
5768 WARN ("RegCloseKey returned %i\n", r);
5769 return ret;
5772 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5773 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5774 if (ret != ERROR_SUCCESS)
5776 r = RegCloseKey (hkSubKey);
5777 if (r != ERROR_SUCCESS)
5778 WARN ("RegCloseKey returned %i\n", r);
5779 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5780 return ret;
5783 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5784 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5786 if (cValues == 0) /* empty key */
5788 r = RegCloseKey (hkSubKey);
5789 if (r != ERROR_SUCCESS)
5790 WARN ("RegCloseKey returned %i\n", r);
5791 *pcbEnumValues = *pnEnumValues = 0;
5792 return ERROR_SUCCESS;
5795 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5797 hHeap = GetProcessHeap ();
5798 if (hHeap == NULL)
5800 ERR ("GetProcessHeap failed\n");
5801 r = RegCloseKey (hkSubKey);
5802 if (r != ERROR_SUCCESS)
5803 WARN ("RegCloseKey returned %i\n", r);
5804 return ERROR_OUTOFMEMORY;
5807 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5808 if (lpValueName == NULL)
5810 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5811 r = RegCloseKey (hkSubKey);
5812 if (r != ERROR_SUCCESS)
5813 WARN ("RegCloseKey returned %i\n", r);
5814 return ERROR_OUTOFMEMORY;
5817 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5818 if (lpValue == NULL)
5820 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5821 if (HeapFree (hHeap, 0, lpValueName) == 0)
5822 WARN ("HeapFree failed with code %i\n", GetLastError ());
5823 r = RegCloseKey (hkSubKey);
5824 if (r != ERROR_SUCCESS)
5825 WARN ("RegCloseKey returned %i\n", r);
5826 return ERROR_OUTOFMEMORY;
5829 TRACE ("pass 1: calculating buffer required for all names and values\n");
5831 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5833 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5835 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5837 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5838 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5839 NULL, NULL, lpValue, &cbValueLen);
5840 if (ret != ERROR_SUCCESS)
5842 if (HeapFree (hHeap, 0, lpValue) == 0)
5843 WARN ("HeapFree failed with code %i\n", GetLastError ());
5844 if (HeapFree (hHeap, 0, lpValueName) == 0)
5845 WARN ("HeapFree failed with code %i\n", GetLastError ());
5846 r = RegCloseKey (hkSubKey);
5847 if (r != ERROR_SUCCESS)
5848 WARN ("RegCloseKey returned %i\n", r);
5849 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5850 return ret;
5853 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5854 debugstr_w (lpValueName), dwIndex,
5855 cbValueNameLen + 1, cbValueLen);
5857 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5858 cbBufSize += cbValueLen;
5861 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5863 *pcbEnumValues = cbBufSize;
5864 *pnEnumValues = cValues;
5866 if (cbEnumValues < cbBufSize) /* buffer too small */
5868 if (HeapFree (hHeap, 0, lpValue) == 0)
5869 WARN ("HeapFree failed with code %i\n", GetLastError ());
5870 if (HeapFree (hHeap, 0, lpValueName) == 0)
5871 WARN ("HeapFree failed with code %i\n", GetLastError ());
5872 r = RegCloseKey (hkSubKey);
5873 if (r != ERROR_SUCCESS)
5874 WARN ("RegCloseKey returned %i\n", r);
5875 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5876 return ERROR_MORE_DATA;
5879 TRACE ("pass 2: copying all names and values to buffer\n");
5881 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5882 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5884 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5886 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5887 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5888 NULL, &dwType, lpValue, &cbValueLen);
5889 if (ret != ERROR_SUCCESS)
5891 if (HeapFree (hHeap, 0, lpValue) == 0)
5892 WARN ("HeapFree failed with code %i\n", GetLastError ());
5893 if (HeapFree (hHeap, 0, lpValueName) == 0)
5894 WARN ("HeapFree failed with code %i\n", GetLastError ());
5895 r = RegCloseKey (hkSubKey);
5896 if (r != ERROR_SUCCESS)
5897 WARN ("RegCloseKey returned %i\n", r);
5898 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5899 return ret;
5902 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5903 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5904 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5905 pEnumValues += cbValueNameLen;
5907 /* return # of *bytes* (including trailing \0), not # of chars */
5908 ppev[dwIndex].cbValueName = cbValueNameLen;
5910 ppev[dwIndex].dwType = dwType;
5912 memcpy (pEnumValues, lpValue, cbValueLen);
5913 ppev[dwIndex].pData = pEnumValues;
5914 pEnumValues += cbValueLen;
5916 ppev[dwIndex].cbData = cbValueLen;
5918 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5919 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5922 if (HeapFree (hHeap, 0, lpValue) == 0)
5924 ret = GetLastError ();
5925 ERR ("HeapFree failed with code %i\n", ret);
5926 if (HeapFree (hHeap, 0, lpValueName) == 0)
5927 WARN ("HeapFree failed with code %i\n", GetLastError ());
5928 r = RegCloseKey (hkSubKey);
5929 if (r != ERROR_SUCCESS)
5930 WARN ("RegCloseKey returned %i\n", r);
5931 return ret;
5934 if (HeapFree (hHeap, 0, lpValueName) == 0)
5936 ret = GetLastError ();
5937 ERR ("HeapFree failed with code %i\n", ret);
5938 r = RegCloseKey (hkSubKey);
5939 if (r != ERROR_SUCCESS)
5940 WARN ("RegCloseKey returned %i\n", r);
5941 return ret;
5944 ret = RegCloseKey (hkSubKey);
5945 if (ret != ERROR_SUCCESS)
5947 ERR ("RegCloseKey returned %i\n", ret);
5948 return ret;
5951 return ERROR_SUCCESS;
5954 /*******************************************************************************
5955 * EnumPrinterDataExA [WINSPOOL.@]
5957 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5958 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5959 * what Windows 2000 SP1 does.
5962 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5963 LPBYTE pEnumValues, DWORD cbEnumValues,
5964 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5966 INT len;
5967 LPWSTR pKeyNameW;
5968 DWORD ret, dwIndex, dwBufSize;
5969 HANDLE hHeap;
5970 LPSTR pBuffer;
5972 TRACE ("%p %s\n", hPrinter, pKeyName);
5974 if (pKeyName == NULL || *pKeyName == 0)
5975 return ERROR_INVALID_PARAMETER;
5977 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5978 if (len == 0)
5980 ret = GetLastError ();
5981 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5982 return ret;
5985 hHeap = GetProcessHeap ();
5986 if (hHeap == NULL)
5988 ERR ("GetProcessHeap failed\n");
5989 return ERROR_OUTOFMEMORY;
5992 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5993 if (pKeyNameW == NULL)
5995 ERR ("Failed to allocate %i bytes from process heap\n",
5996 (LONG)(len * sizeof (WCHAR)));
5997 return ERROR_OUTOFMEMORY;
6000 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6002 ret = GetLastError ();
6003 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6004 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6005 WARN ("HeapFree failed with code %i\n", GetLastError ());
6006 return ret;
6009 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6010 pcbEnumValues, pnEnumValues);
6011 if (ret != ERROR_SUCCESS)
6013 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6014 WARN ("HeapFree failed with code %i\n", GetLastError ());
6015 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6016 return ret;
6019 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6021 ret = GetLastError ();
6022 ERR ("HeapFree failed with code %i\n", ret);
6023 return ret;
6026 if (*pnEnumValues == 0) /* empty key */
6027 return ERROR_SUCCESS;
6029 dwBufSize = 0;
6030 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6032 PPRINTER_ENUM_VALUESW ppev =
6033 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6035 if (dwBufSize < ppev->cbValueName)
6036 dwBufSize = ppev->cbValueName;
6038 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6039 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6040 dwBufSize = ppev->cbData;
6043 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6045 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6046 if (pBuffer == NULL)
6048 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6049 return ERROR_OUTOFMEMORY;
6052 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6054 PPRINTER_ENUM_VALUESW ppev =
6055 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6057 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6058 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6059 NULL);
6060 if (len == 0)
6062 ret = GetLastError ();
6063 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6064 if (HeapFree (hHeap, 0, pBuffer) == 0)
6065 WARN ("HeapFree failed with code %i\n", GetLastError ());
6066 return ret;
6069 memcpy (ppev->pValueName, pBuffer, len);
6071 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6073 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6074 ppev->dwType != REG_MULTI_SZ)
6075 continue;
6077 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6078 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6079 if (len == 0)
6081 ret = GetLastError ();
6082 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6083 if (HeapFree (hHeap, 0, pBuffer) == 0)
6084 WARN ("HeapFree failed with code %i\n", GetLastError ());
6085 return ret;
6088 memcpy (ppev->pData, pBuffer, len);
6090 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6091 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6094 if (HeapFree (hHeap, 0, pBuffer) == 0)
6096 ret = GetLastError ();
6097 ERR ("HeapFree failed with code %i\n", ret);
6098 return ret;
6101 return ERROR_SUCCESS;
6104 /******************************************************************************
6105 * AbortPrinter (WINSPOOL.@)
6107 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6109 FIXME("(%p), stub!\n", hPrinter);
6110 return TRUE;
6113 /******************************************************************************
6114 * AddPortA (WINSPOOL.@)
6116 * See AddPortW.
6119 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6121 LPWSTR nameW = NULL;
6122 LPWSTR monitorW = NULL;
6123 DWORD len;
6124 BOOL res;
6126 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6128 if (pName) {
6129 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6130 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6131 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6134 if (pMonitorName) {
6135 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6136 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6137 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6139 res = AddPortW(nameW, hWnd, monitorW);
6140 HeapFree(GetProcessHeap(), 0, nameW);
6141 HeapFree(GetProcessHeap(), 0, monitorW);
6142 return res;
6145 /******************************************************************************
6146 * AddPortW (WINSPOOL.@)
6148 * Add a Port for a specific Monitor
6150 * PARAMS
6151 * pName [I] Servername or NULL (local Computer)
6152 * hWnd [I] Handle to parent Window for the Dialog-Box
6153 * pMonitorName [I] Name of the Monitor that manage the Port
6155 * RETURNS
6156 * Success: TRUE
6157 * Failure: FALSE
6160 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6162 monitor_t * pm;
6163 monitor_t * pui;
6164 DWORD res;
6166 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6168 if (pName && pName[0]) {
6169 SetLastError(ERROR_INVALID_PARAMETER);
6170 return FALSE;
6173 if (!pMonitorName) {
6174 SetLastError(RPC_X_NULL_REF_POINTER);
6175 return FALSE;
6178 /* an empty Monitorname is Invalid */
6179 if (!pMonitorName[0]) {
6180 SetLastError(ERROR_NOT_SUPPORTED);
6181 return FALSE;
6184 pm = monitor_load(pMonitorName, NULL);
6185 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
6186 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
6187 TRACE("got %d with %u\n", res, GetLastError());
6188 res = TRUE;
6190 else
6192 pui = monitor_loadui(pm);
6193 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
6194 TRACE("use %p: %s\n", pui, debugstr_w(pui->dllname));
6195 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
6196 TRACE("got %d with %u\n", res, GetLastError());
6197 res = TRUE;
6199 else
6201 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName),
6202 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6204 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6205 SetLastError(ERROR_NOT_SUPPORTED);
6206 res = FALSE;
6208 monitor_unload(pui);
6210 monitor_unload(pm);
6211 TRACE("returning %d with %u\n", res, GetLastError());
6212 return res;
6215 /******************************************************************************
6216 * AddPortExA (WINSPOOL.@)
6218 * See AddPortExW.
6221 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6223 PORT_INFO_2W pi2W;
6224 PORT_INFO_2A * pi2A;
6225 LPWSTR nameW = NULL;
6226 LPWSTR monitorW = NULL;
6227 DWORD len;
6228 BOOL res;
6230 pi2A = (PORT_INFO_2A *) pBuffer;
6232 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6233 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6235 if ((level < 1) || (level > 2)) {
6236 SetLastError(ERROR_INVALID_LEVEL);
6237 return FALSE;
6240 if (!pi2A) {
6241 SetLastError(ERROR_INVALID_PARAMETER);
6242 return FALSE;
6245 if (pName) {
6246 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6247 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6248 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6251 if (pMonitorName) {
6252 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6253 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6254 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6257 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6259 if (pi2A->pPortName) {
6260 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6261 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6262 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6265 if (level > 1) {
6266 if (pi2A->pMonitorName) {
6267 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6268 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6269 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6272 if (pi2A->pDescription) {
6273 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6274 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6275 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6277 pi2W.fPortType = pi2A->fPortType;
6278 pi2W.Reserved = pi2A->Reserved;
6281 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6283 HeapFree(GetProcessHeap(), 0, nameW);
6284 HeapFree(GetProcessHeap(), 0, monitorW);
6285 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6286 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6287 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6288 return res;
6292 /******************************************************************************
6293 * AddPortExW (WINSPOOL.@)
6295 * Add a Port for a specific Monitor, without presenting a user interface
6297 * PARAMS
6298 * pName [I] Servername or NULL (local Computer)
6299 * level [I] Structure-Level (1 or 2) for pBuffer
6300 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6301 * pMonitorName [I] Name of the Monitor that manage the Port
6303 * RETURNS
6304 * Success: TRUE
6305 * Failure: FALSE
6308 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6310 PORT_INFO_2W * pi2;
6311 monitor_t * pm;
6312 DWORD res = FALSE;
6314 pi2 = (PORT_INFO_2W *) pBuffer;
6316 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6317 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6318 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6319 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6322 if ((level < 1) || (level > 2)) {
6323 SetLastError(ERROR_INVALID_LEVEL);
6324 return FALSE;
6327 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6328 SetLastError(ERROR_INVALID_PARAMETER);
6329 return FALSE;
6332 /* load the Monitor */
6333 pm = monitor_load(pMonitorName, NULL);
6334 if (!pm) {
6335 SetLastError(ERROR_INVALID_PARAMETER);
6336 return FALSE;
6339 if (pm->monitor && pm->monitor->pfnAddPortEx) {
6340 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
6341 TRACE("got %u with %u\n", res, GetLastError());
6343 else
6345 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName), pm->monitor);
6347 monitor_unload(pm);
6348 return res;
6351 /******************************************************************************
6352 * AddPrinterConnectionA (WINSPOOL.@)
6354 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6356 FIXME("%s\n", debugstr_a(pName));
6357 return FALSE;
6360 /******************************************************************************
6361 * AddPrinterConnectionW (WINSPOOL.@)
6363 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6365 FIXME("%s\n", debugstr_w(pName));
6366 return FALSE;
6369 /******************************************************************************
6370 * AddPrinterDriverExW (WINSPOOL.@)
6372 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
6373 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6375 FIXME("%s %d %p %d\n", debugstr_w(pName),
6376 Level, pDriverInfo, dwFileCopyFlags);
6377 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
6378 return FALSE;
6381 /******************************************************************************
6382 * AddPrinterDriverExA (WINSPOOL.@)
6384 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
6385 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6387 FIXME("%s %d %p %d\n", debugstr_a(pName),
6388 Level, pDriverInfo, dwFileCopyFlags);
6389 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
6390 return FALSE;
6393 /******************************************************************************
6394 * ConfigurePortA (WINSPOOL.@)
6396 * See ConfigurePortW.
6399 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6401 LPWSTR nameW = NULL;
6402 LPWSTR portW = NULL;
6403 INT len;
6404 DWORD res;
6406 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6408 /* convert servername to unicode */
6409 if (pName) {
6410 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6411 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6412 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6415 /* convert portname to unicode */
6416 if (pPortName) {
6417 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6418 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6419 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6422 res = ConfigurePortW(nameW, hWnd, portW);
6423 HeapFree(GetProcessHeap(), 0, nameW);
6424 HeapFree(GetProcessHeap(), 0, portW);
6425 return res;
6428 /******************************************************************************
6429 * ConfigurePortW (WINSPOOL.@)
6431 * Display the Configuration-Dialog for a specific Port
6433 * PARAMS
6434 * pName [I] Servername or NULL (local Computer)
6435 * hWnd [I] Handle to parent Window for the Dialog-Box
6436 * pPortName [I] Name of the Port, that should be configured
6438 * RETURNS
6439 * Success: TRUE
6440 * Failure: FALSE
6443 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6445 monitor_t * pm;
6446 monitor_t * pui;
6447 DWORD res;
6449 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6451 if (pName && pName[0]) {
6452 SetLastError(ERROR_INVALID_PARAMETER);
6453 return FALSE;
6456 if (!pPortName) {
6457 SetLastError(RPC_X_NULL_REF_POINTER);
6458 return FALSE;
6461 /* an empty Portname is Invalid, but can popup a Dialog */
6462 if (!pPortName[0]) {
6463 SetLastError(ERROR_NOT_SUPPORTED);
6464 return FALSE;
6467 pm = monitor_load_by_port(pPortName);
6468 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6469 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6470 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6471 TRACE("got %d with %u\n", res, GetLastError());
6473 else
6475 pui = monitor_loadui(pm);
6476 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6477 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6478 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6479 TRACE("got %d with %u\n", res, GetLastError());
6481 else
6483 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6484 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6486 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6487 SetLastError(ERROR_NOT_SUPPORTED);
6488 res = FALSE;
6490 monitor_unload(pui);
6492 monitor_unload(pm);
6494 TRACE("returning %d with %u\n", res, GetLastError());
6495 return res;
6498 /******************************************************************************
6499 * ConnectToPrinterDlg (WINSPOOL.@)
6501 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6503 FIXME("%p %x\n", hWnd, Flags);
6504 return NULL;
6507 /******************************************************************************
6508 * DeletePrinterConnectionA (WINSPOOL.@)
6510 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6512 FIXME("%s\n", debugstr_a(pName));
6513 return TRUE;
6516 /******************************************************************************
6517 * DeletePrinterConnectionW (WINSPOOL.@)
6519 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6521 FIXME("%s\n", debugstr_w(pName));
6522 return TRUE;
6525 /******************************************************************************
6526 * DeletePrinterDriverExW (WINSPOOL.@)
6528 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6529 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6531 HKEY hkey_drivers;
6532 BOOL ret = FALSE;
6534 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6535 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6537 if(pName && pName[0])
6539 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6540 SetLastError(ERROR_INVALID_PARAMETER);
6541 return FALSE;
6544 if(dwDeleteFlag)
6546 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6547 SetLastError(ERROR_INVALID_PARAMETER);
6548 return FALSE;
6551 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6553 if(!hkey_drivers)
6555 ERR("Can't open drivers key\n");
6556 return FALSE;
6559 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6560 ret = TRUE;
6562 RegCloseKey(hkey_drivers);
6564 return ret;
6567 /******************************************************************************
6568 * DeletePrinterDriverExA (WINSPOOL.@)
6570 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6571 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6573 UNICODE_STRING NameW, EnvW, DriverW;
6574 BOOL ret;
6576 asciitounicode(&NameW, pName);
6577 asciitounicode(&EnvW, pEnvironment);
6578 asciitounicode(&DriverW, pDriverName);
6580 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6582 RtlFreeUnicodeString(&DriverW);
6583 RtlFreeUnicodeString(&EnvW);
6584 RtlFreeUnicodeString(&NameW);
6586 return ret;
6589 /******************************************************************************
6590 * DeletePrinterDataExW (WINSPOOL.@)
6592 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6593 LPCWSTR pValueName)
6595 FIXME("%p %s %s\n", hPrinter,
6596 debugstr_w(pKeyName), debugstr_w(pValueName));
6597 return ERROR_INVALID_PARAMETER;
6600 /******************************************************************************
6601 * DeletePrinterDataExA (WINSPOOL.@)
6603 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6604 LPCSTR pValueName)
6606 FIXME("%p %s %s\n", hPrinter,
6607 debugstr_a(pKeyName), debugstr_a(pValueName));
6608 return ERROR_INVALID_PARAMETER;
6611 /******************************************************************************
6612 * DeletePrintProcessorA (WINSPOOL.@)
6614 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6616 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6617 debugstr_a(pPrintProcessorName));
6618 return TRUE;
6621 /******************************************************************************
6622 * DeletePrintProcessorW (WINSPOOL.@)
6624 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6626 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6627 debugstr_w(pPrintProcessorName));
6628 return TRUE;
6631 /******************************************************************************
6632 * DeletePrintProvidorA (WINSPOOL.@)
6634 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6636 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6637 debugstr_a(pPrintProviderName));
6638 return TRUE;
6641 /******************************************************************************
6642 * DeletePrintProvidorW (WINSPOOL.@)
6644 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6646 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6647 debugstr_w(pPrintProviderName));
6648 return TRUE;
6651 /******************************************************************************
6652 * EnumFormsA (WINSPOOL.@)
6654 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6655 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6657 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6658 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6659 return FALSE;
6662 /******************************************************************************
6663 * EnumFormsW (WINSPOOL.@)
6665 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6666 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6668 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6669 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6670 return FALSE;
6673 /*****************************************************************************
6674 * EnumMonitorsA [WINSPOOL.@]
6676 * See EnumMonitorsW.
6679 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6680 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6682 BOOL res;
6683 LPBYTE bufferW = NULL;
6684 LPWSTR nameW = NULL;
6685 DWORD needed = 0;
6686 DWORD numentries = 0;
6687 INT len;
6689 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6690 cbBuf, pcbNeeded, pcReturned);
6692 /* convert servername to unicode */
6693 if (pName) {
6694 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6695 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6696 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6698 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6699 needed = cbBuf * sizeof(WCHAR);
6700 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6701 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6703 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6704 if (pcbNeeded) needed = *pcbNeeded;
6705 /* HeapReAlloc return NULL, when bufferW was NULL */
6706 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6707 HeapAlloc(GetProcessHeap(), 0, needed);
6709 /* Try again with the large Buffer */
6710 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6712 numentries = pcReturned ? *pcReturned : 0;
6713 needed = 0;
6715 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6716 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6718 if (res) {
6719 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6720 DWORD entrysize = 0;
6721 DWORD index;
6722 LPSTR ptr;
6723 LPMONITOR_INFO_2W mi2w;
6724 LPMONITOR_INFO_2A mi2a;
6726 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6727 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6729 /* First pass: calculate the size for all Entries */
6730 mi2w = (LPMONITOR_INFO_2W) bufferW;
6731 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6732 index = 0;
6733 while (index < numentries) {
6734 index++;
6735 needed += entrysize; /* MONITOR_INFO_?A */
6736 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6738 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6739 NULL, 0, NULL, NULL);
6740 if (Level > 1) {
6741 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6742 NULL, 0, NULL, NULL);
6743 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6744 NULL, 0, NULL, NULL);
6746 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6747 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6748 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6751 /* check for errors and quit on failure */
6752 if (cbBuf < needed) {
6753 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6754 res = FALSE;
6755 goto emA_cleanup;
6757 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6758 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6759 cbBuf -= len ; /* free Bytes in the user-Buffer */
6760 mi2w = (LPMONITOR_INFO_2W) bufferW;
6761 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6762 index = 0;
6763 /* Second Pass: Fill the User Buffer (if we have one) */
6764 while ((index < numentries) && pMonitors) {
6765 index++;
6766 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6767 mi2a->pName = ptr;
6768 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6769 ptr, cbBuf , NULL, NULL);
6770 ptr += len;
6771 cbBuf -= len;
6772 if (Level > 1) {
6773 mi2a->pEnvironment = ptr;
6774 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6775 ptr, cbBuf, NULL, NULL);
6776 ptr += len;
6777 cbBuf -= len;
6779 mi2a->pDLLName = ptr;
6780 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6781 ptr, cbBuf, NULL, NULL);
6782 ptr += len;
6783 cbBuf -= len;
6785 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6786 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6787 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6790 emA_cleanup:
6791 if (pcbNeeded) *pcbNeeded = needed;
6792 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6794 HeapFree(GetProcessHeap(), 0, nameW);
6795 HeapFree(GetProcessHeap(), 0, bufferW);
6797 TRACE("returning %d with %d (%d byte for %d entries)\n",
6798 (res), GetLastError(), needed, numentries);
6800 return (res);
6804 /*****************************************************************************
6805 * EnumMonitorsW [WINSPOOL.@]
6807 * Enumerate available Port-Monitors
6809 * PARAMS
6810 * pName [I] Servername or NULL (local Computer)
6811 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6812 * pMonitors [O] PTR to Buffer that receives the Result
6813 * cbBuf [I] Size of Buffer at pMonitors
6814 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6815 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6817 * RETURNS
6818 * Success: TRUE
6819 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6821 * NOTES
6822 * Windows reads the Registry once and cache the Results.
6824 *| Language-Monitors are also installed in the same Registry-Location but
6825 *| they are filtered in Windows (not returned by EnumMonitors).
6826 *| We do no filtering to simplify our Code.
6829 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6830 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6832 DWORD needed = 0;
6833 DWORD numentries = 0;
6834 BOOL res = FALSE;
6836 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6837 cbBuf, pcbNeeded, pcReturned);
6839 if (pName && (lstrlenW(pName))) {
6840 FIXME("for Server %s not implemented\n", debugstr_w(pName));
6841 SetLastError(ERROR_ACCESS_DENIED);
6842 goto emW_cleanup;
6845 /* Level is not checked in win9x */
6846 if (!Level || (Level > 2)) {
6847 WARN("level (%d) is ignored in win9x\n", Level);
6848 SetLastError(ERROR_INVALID_LEVEL);
6849 goto emW_cleanup;
6851 if (!pcbNeeded) {
6852 SetLastError(RPC_X_NULL_REF_POINTER);
6853 goto emW_cleanup;
6856 /* Scan all Monitor-Keys */
6857 numentries = 0;
6858 needed = get_local_monitors(Level, NULL, 0, &numentries);
6860 /* we calculated the needed buffersize. now do the error-checks */
6861 if (cbBuf < needed) {
6862 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6863 goto emW_cleanup;
6865 else if (!pMonitors || !pcReturned) {
6866 SetLastError(RPC_X_NULL_REF_POINTER);
6867 goto emW_cleanup;
6870 /* fill the Buffer with the Monitor-Keys */
6871 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
6872 res = TRUE;
6874 emW_cleanup:
6875 if (pcbNeeded) *pcbNeeded = needed;
6876 if (pcReturned) *pcReturned = numentries;
6878 TRACE("returning %d with %d (%d byte for %d entries)\n",
6879 res, GetLastError(), needed, numentries);
6881 return (res);
6884 /******************************************************************************
6885 * XcvDataW (WINSPOOL.@)
6887 * Execute commands in the Printmonitor DLL
6889 * PARAMS
6890 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6891 * pszDataName [i] Name of the command to execute
6892 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6893 * cbInputData [i] Size in Bytes of Buffer at pInputData
6894 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6895 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6896 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6897 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6899 * RETURNS
6900 * Success: TRUE
6901 * Failure: FALSE
6903 * NOTES
6904 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6905 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6907 * Minimal List of commands, that a Printmonitor DLL should support:
6909 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6910 *| "AddPort" : Add a Port
6911 *| "DeletePort": Delete a Port
6913 * Many Printmonitors support additional commands. Examples for localspl.dll:
6914 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6915 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6918 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6919 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6920 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6922 opened_printer_t *printer;
6924 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6925 pInputData, cbInputData, pOutputData,
6926 cbOutputData, pcbOutputNeeded, pdwStatus);
6928 printer = get_opened_printer(hXcv);
6929 if (!printer || (!printer->hXcv)) {
6930 SetLastError(ERROR_INVALID_HANDLE);
6931 return FALSE;
6934 if (!pcbOutputNeeded) {
6935 SetLastError(ERROR_INVALID_PARAMETER);
6936 return FALSE;
6939 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6940 SetLastError(RPC_X_NULL_REF_POINTER);
6941 return FALSE;
6944 *pcbOutputNeeded = 0;
6946 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
6947 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
6949 return TRUE;
6952 /*****************************************************************************
6953 * EnumPrinterDataA [WINSPOOL.@]
6956 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6957 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6958 DWORD cbData, LPDWORD pcbData )
6960 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6961 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6962 return ERROR_NO_MORE_ITEMS;
6965 /*****************************************************************************
6966 * EnumPrinterDataW [WINSPOOL.@]
6969 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6970 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6971 DWORD cbData, LPDWORD pcbData )
6973 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6974 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6975 return ERROR_NO_MORE_ITEMS;
6978 /*****************************************************************************
6979 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6982 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6983 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6984 LPDWORD pcbNeeded, LPDWORD pcReturned)
6986 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6987 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6988 pcbNeeded, pcReturned);
6989 return FALSE;
6992 /*****************************************************************************
6993 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6996 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6997 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6998 LPDWORD pcbNeeded, LPDWORD pcReturned)
7000 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7001 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7002 pcbNeeded, pcReturned);
7003 return FALSE;
7006 /*****************************************************************************
7007 * EnumPrintProcessorsA [WINSPOOL.@]
7010 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7011 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7013 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
7014 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
7015 return FALSE;
7018 /*****************************************************************************
7019 * EnumPrintProcessorsW [WINSPOOL.@]
7022 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7023 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7025 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7026 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
7027 cbBuf, pcbNeeded, pcbReturned);
7028 return FALSE;
7031 /*****************************************************************************
7032 * ExtDeviceMode [WINSPOOL.@]
7035 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7036 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7037 DWORD fMode)
7039 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7040 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7041 debugstr_a(pProfile), fMode);
7042 return -1;
7045 /*****************************************************************************
7046 * FindClosePrinterChangeNotification [WINSPOOL.@]
7049 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7051 FIXME("Stub: %p\n", hChange);
7052 return TRUE;
7055 /*****************************************************************************
7056 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7059 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7060 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7062 FIXME("Stub: %p %x %x %p\n",
7063 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7064 return INVALID_HANDLE_VALUE;
7067 /*****************************************************************************
7068 * FindNextPrinterChangeNotification [WINSPOOL.@]
7071 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7072 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7074 FIXME("Stub: %p %p %p %p\n",
7075 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7076 return FALSE;
7079 /*****************************************************************************
7080 * FreePrinterNotifyInfo [WINSPOOL.@]
7083 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7085 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7086 return TRUE;
7089 /*****************************************************************************
7090 * string_to_buf
7092 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7093 * ansi depending on the unicode parameter.
7095 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7097 if(!str)
7099 *size = 0;
7100 return TRUE;
7103 if(unicode)
7105 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7106 if(*size <= cb)
7108 memcpy(ptr, str, *size);
7109 return TRUE;
7111 return FALSE;
7113 else
7115 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7116 if(*size <= cb)
7118 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7119 return TRUE;
7121 return FALSE;
7125 /*****************************************************************************
7126 * get_job_info_1
7128 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7129 LPDWORD pcbNeeded, BOOL unicode)
7131 DWORD size, left = cbBuf;
7132 BOOL space = (cbBuf > 0);
7133 LPBYTE ptr = buf;
7135 *pcbNeeded = 0;
7137 if(space)
7139 ji1->JobId = job->job_id;
7142 string_to_buf(job->document_title, ptr, left, &size, unicode);
7143 if(space && size <= left)
7145 ji1->pDocument = (LPWSTR)ptr;
7146 ptr += size;
7147 left -= size;
7149 else
7150 space = FALSE;
7151 *pcbNeeded += size;
7153 return space;
7156 /*****************************************************************************
7157 * get_job_info_2
7159 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7160 LPDWORD pcbNeeded, BOOL unicode)
7162 DWORD size, left = cbBuf;
7163 BOOL space = (cbBuf > 0);
7164 LPBYTE ptr = buf;
7166 *pcbNeeded = 0;
7168 if(space)
7170 ji2->JobId = job->job_id;
7173 string_to_buf(job->document_title, ptr, left, &size, unicode);
7174 if(space && size <= left)
7176 ji2->pDocument = (LPWSTR)ptr;
7177 ptr += size;
7178 left -= size;
7180 else
7181 space = FALSE;
7182 *pcbNeeded += size;
7184 return space;
7187 /*****************************************************************************
7188 * get_job_info
7190 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7191 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7193 BOOL ret = FALSE;
7194 DWORD needed = 0, size;
7195 job_t *job;
7196 LPBYTE ptr = pJob;
7198 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7200 EnterCriticalSection(&printer_handles_cs);
7201 job = get_job(hPrinter, JobId);
7202 if(!job)
7203 goto end;
7205 switch(Level)
7207 case 1:
7208 size = sizeof(JOB_INFO_1W);
7209 if(cbBuf >= size)
7211 cbBuf -= size;
7212 ptr += size;
7213 memset(pJob, 0, size);
7215 else
7216 cbBuf = 0;
7217 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7218 needed += size;
7219 break;
7221 case 2:
7222 size = sizeof(JOB_INFO_2W);
7223 if(cbBuf >= size)
7225 cbBuf -= size;
7226 ptr += size;
7227 memset(pJob, 0, size);
7229 else
7230 cbBuf = 0;
7231 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7232 needed += size;
7233 break;
7235 case 3:
7236 size = sizeof(JOB_INFO_3);
7237 if(cbBuf >= size)
7239 cbBuf -= size;
7240 memset(pJob, 0, size);
7241 ret = TRUE;
7243 else
7244 cbBuf = 0;
7245 needed = size;
7246 break;
7248 default:
7249 SetLastError(ERROR_INVALID_LEVEL);
7250 goto end;
7252 if(pcbNeeded)
7253 *pcbNeeded = needed;
7254 end:
7255 LeaveCriticalSection(&printer_handles_cs);
7256 return ret;
7259 /*****************************************************************************
7260 * GetJobA [WINSPOOL.@]
7263 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7264 DWORD cbBuf, LPDWORD pcbNeeded)
7266 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7269 /*****************************************************************************
7270 * GetJobW [WINSPOOL.@]
7273 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7274 DWORD cbBuf, LPDWORD pcbNeeded)
7276 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7279 /*****************************************************************************
7280 * schedule_lpr
7282 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7284 char *unixname, *queue, *cmd;
7285 char fmt[] = "lpr -P%s %s";
7286 DWORD len;
7288 if(!(unixname = wine_get_unix_file_name(filename)))
7289 return FALSE;
7291 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7292 queue = HeapAlloc(GetProcessHeap(), 0, len);
7293 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7295 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7296 sprintf(cmd, fmt, queue, unixname);
7298 TRACE("printing with: %s\n", cmd);
7299 system(cmd);
7301 HeapFree(GetProcessHeap(), 0, cmd);
7302 HeapFree(GetProcessHeap(), 0, queue);
7303 HeapFree(GetProcessHeap(), 0, unixname);
7304 return TRUE;
7307 /*****************************************************************************
7308 * schedule_cups
7310 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7312 #ifdef SONAME_LIBCUPS
7313 if(pcupsPrintFile)
7315 char *unixname, *queue, *doc_titleA;
7316 DWORD len;
7317 BOOL ret;
7319 if(!(unixname = wine_get_unix_file_name(filename)))
7320 return FALSE;
7322 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7323 queue = HeapAlloc(GetProcessHeap(), 0, len);
7324 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7326 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
7327 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
7328 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
7330 TRACE("printing via cups\n");
7331 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
7332 HeapFree(GetProcessHeap(), 0, doc_titleA);
7333 HeapFree(GetProcessHeap(), 0, queue);
7334 HeapFree(GetProcessHeap(), 0, unixname);
7335 return ret;
7337 else
7338 #endif
7340 return schedule_lpr(printer_name, filename);
7344 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7346 LPWSTR filename;
7348 switch(msg)
7350 case WM_INITDIALOG:
7351 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7352 return TRUE;
7354 case WM_COMMAND:
7355 if(HIWORD(wparam) == BN_CLICKED)
7357 if(LOWORD(wparam) == IDOK)
7359 HANDLE hf;
7360 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7361 LPWSTR *output;
7363 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7364 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7366 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7368 WCHAR caption[200], message[200];
7369 int mb_ret;
7371 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7372 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7373 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7374 if(mb_ret == IDCANCEL)
7376 HeapFree(GetProcessHeap(), 0, filename);
7377 return TRUE;
7380 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7381 if(hf == INVALID_HANDLE_VALUE)
7383 WCHAR caption[200], message[200];
7385 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7386 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7387 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7388 HeapFree(GetProcessHeap(), 0, filename);
7389 return TRUE;
7391 CloseHandle(hf);
7392 DeleteFileW(filename);
7393 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7394 *output = filename;
7395 EndDialog(hwnd, IDOK);
7396 return TRUE;
7398 if(LOWORD(wparam) == IDCANCEL)
7400 EndDialog(hwnd, IDCANCEL);
7401 return TRUE;
7404 return FALSE;
7406 return FALSE;
7409 /*****************************************************************************
7410 * get_filename
7412 static BOOL get_filename(LPWSTR *filename)
7414 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7415 file_dlg_proc, (LPARAM)filename) == IDOK;
7418 /*****************************************************************************
7419 * schedule_file
7421 static BOOL schedule_file(LPCWSTR filename)
7423 LPWSTR output = NULL;
7425 if(get_filename(&output))
7427 TRACE("copy to %s\n", debugstr_w(output));
7428 CopyFileW(filename, output, FALSE);
7429 HeapFree(GetProcessHeap(), 0, output);
7430 return TRUE;
7432 return FALSE;
7435 /*****************************************************************************
7436 * schedule_pipe
7438 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7440 #ifdef HAVE_FORK
7441 char *unixname, *cmdA;
7442 DWORD len;
7443 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7444 BOOL ret = FALSE;
7445 char buf[1024];
7447 if(!(unixname = wine_get_unix_file_name(filename)))
7448 return FALSE;
7450 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
7451 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7452 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
7454 TRACE("printing with: %s\n", cmdA);
7456 if((file_fd = open(unixname, O_RDONLY)) == -1)
7457 goto end;
7459 if (pipe(fds))
7461 ERR("pipe() failed!\n");
7462 goto end;
7465 if (fork() == 0)
7467 close(0);
7468 dup2(fds[0], 0);
7469 close(fds[1]);
7471 /* reset signals that we previously set to SIG_IGN */
7472 signal(SIGPIPE, SIG_DFL);
7473 signal(SIGCHLD, SIG_DFL);
7475 execl("/bin/sh", "/bin/sh", "-c", cmdA, (char*)0);
7476 _exit(1);
7479 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7480 write(fds[1], buf, no_read);
7482 ret = TRUE;
7484 end:
7485 if(file_fd != -1) close(file_fd);
7486 if(fds[0] != -1) close(fds[0]);
7487 if(fds[1] != -1) close(fds[1]);
7489 HeapFree(GetProcessHeap(), 0, cmdA);
7490 HeapFree(GetProcessHeap(), 0, unixname);
7491 return ret;
7492 #else
7493 return FALSE;
7494 #endif
7497 /*****************************************************************************
7498 * schedule_unixfile
7500 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7502 int in_fd, out_fd, no_read;
7503 char buf[1024];
7504 BOOL ret = FALSE;
7505 char *unixname, *outputA;
7506 DWORD len;
7508 if(!(unixname = wine_get_unix_file_name(filename)))
7509 return FALSE;
7511 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
7512 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7513 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
7515 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7516 in_fd = open(unixname, O_RDONLY);
7517 if(out_fd == -1 || in_fd == -1)
7518 goto end;
7520 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7521 write(out_fd, buf, no_read);
7523 ret = TRUE;
7524 end:
7525 if(in_fd != -1) close(in_fd);
7526 if(out_fd != -1) close(out_fd);
7527 HeapFree(GetProcessHeap(), 0, outputA);
7528 HeapFree(GetProcessHeap(), 0, unixname);
7529 return ret;
7532 /*****************************************************************************
7533 * ScheduleJob [WINSPOOL.@]
7536 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7538 opened_printer_t *printer;
7539 BOOL ret = FALSE;
7540 struct list *cursor, *cursor2;
7542 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7543 EnterCriticalSection(&printer_handles_cs);
7544 printer = get_opened_printer(hPrinter);
7545 if(!printer)
7546 goto end;
7548 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7550 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7551 HANDLE hf;
7553 if(job->job_id != dwJobID) continue;
7555 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7556 if(hf != INVALID_HANDLE_VALUE)
7558 PRINTER_INFO_5W *pi5;
7559 DWORD needed;
7560 HKEY hkey;
7561 WCHAR output[1024];
7562 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7563 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7565 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7566 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7567 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7568 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7569 debugstr_w(pi5->pPortName));
7571 output[0] = 0;
7573 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7574 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7576 DWORD type, count = sizeof(output);
7577 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7578 RegCloseKey(hkey);
7580 if(output[0] == '|')
7582 schedule_pipe(output + 1, job->filename);
7584 else if(output[0])
7586 schedule_unixfile(output, job->filename);
7588 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7590 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7592 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7594 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7596 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7598 schedule_file(job->filename);
7600 else
7602 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7604 HeapFree(GetProcessHeap(), 0, pi5);
7605 CloseHandle(hf);
7606 DeleteFileW(job->filename);
7608 list_remove(cursor);
7609 HeapFree(GetProcessHeap(), 0, job->document_title);
7610 HeapFree(GetProcessHeap(), 0, job->filename);
7611 HeapFree(GetProcessHeap(), 0, job);
7612 ret = TRUE;
7613 break;
7615 end:
7616 LeaveCriticalSection(&printer_handles_cs);
7617 return ret;
7620 /*****************************************************************************
7621 * StartDocDlgA [WINSPOOL.@]
7623 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7625 UNICODE_STRING usBuffer;
7626 DOCINFOW docW;
7627 LPWSTR retW;
7628 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7629 LPSTR ret = NULL;
7631 docW.cbSize = sizeof(docW);
7632 if (doc->lpszDocName)
7634 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7635 if (!(docW.lpszDocName = docnameW)) return NULL;
7637 if (doc->lpszOutput)
7639 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7640 if (!(docW.lpszOutput = outputW)) return NULL;
7642 if (doc->lpszDatatype)
7644 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7645 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7647 docW.fwType = doc->fwType;
7649 retW = StartDocDlgW(hPrinter, &docW);
7651 if(retW)
7653 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7654 ret = HeapAlloc(GetProcessHeap(), 0, len);
7655 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7656 HeapFree(GetProcessHeap(), 0, retW);
7659 HeapFree(GetProcessHeap(), 0, datatypeW);
7660 HeapFree(GetProcessHeap(), 0, outputW);
7661 HeapFree(GetProcessHeap(), 0, docnameW);
7663 return ret;
7666 /*****************************************************************************
7667 * StartDocDlgW [WINSPOOL.@]
7669 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7670 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7671 * port is "FILE:". Also returns the full path if passed a relative path.
7673 * The caller should free the returned string from the process heap.
7675 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7677 LPWSTR ret = NULL;
7678 DWORD len, attr;
7680 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7682 PRINTER_INFO_5W *pi5;
7683 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7684 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7685 return NULL;
7686 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7687 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7688 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7690 HeapFree(GetProcessHeap(), 0, pi5);
7691 return NULL;
7693 HeapFree(GetProcessHeap(), 0, pi5);
7696 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7698 LPWSTR name;
7700 if (get_filename(&name))
7702 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7704 HeapFree(GetProcessHeap(), 0, name);
7705 return NULL;
7707 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7708 GetFullPathNameW(name, len, ret, NULL);
7709 HeapFree(GetProcessHeap(), 0, name);
7711 return ret;
7714 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7715 return NULL;
7717 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7718 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7720 attr = GetFileAttributesW(ret);
7721 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7723 HeapFree(GetProcessHeap(), 0, ret);
7724 ret = NULL;
7726 return ret;