wininet: Use proc instead of enum in INTERNETOPENURLW request.
[wine/dibdrv.git] / dlls / winspool.drv / info.c
blobf357c3cbf797a36509147a05ea1589c33192538c
1 /*
2 * WINSPOOL functions
4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005, 2006 Detlef Riekenberg
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "config.h"
27 #include "wine/port.h"
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <stddef.h>
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif
38 #include <signal.h>
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
41 # ifndef SONAME_LIBCUPS
42 # define SONAME_LIBCUPS "libcups.so"
43 # endif
44 #endif
46 #define NONAMELESSUNION
47 #define NONAMELESSSTRUCT
48 #include "wine/library.h"
49 #include "windef.h"
50 #include "winbase.h"
51 #include "winuser.h"
52 #include "winerror.h"
53 #include "winreg.h"
54 #include "wingdi.h"
55 #include "winspool.h"
56 #include "winternl.h"
57 #include "wine/windef16.h"
58 #include "wine/unicode.h"
59 #include "wine/debug.h"
60 #include "wine/list.h"
61 #include "winnls.h"
63 #include "ddk/winsplp.h"
64 #include "wspool.h"
66 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
68 /* ############################### */
70 static CRITICAL_SECTION monitor_handles_cs;
71 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
73 0, 0, &monitor_handles_cs,
74 { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
75 0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
77 static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
80 static CRITICAL_SECTION printer_handles_cs;
81 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
83 0, 0, &printer_handles_cs,
84 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
85 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
87 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
89 /* ############################### */
91 typedef struct {
92 struct list entry;
93 LPWSTR name;
94 LPWSTR dllname;
95 PMONITORUI monitorUI;
96 LPMONITOR monitor;
97 HMODULE hdll;
98 DWORD refcount;
99 DWORD dwMonitorSize;
100 LPPORT_INFO_2W cache; /* cached PORT_INFO_2W data */
101 DWORD pi1_needed; /* size for PORT_INFO_1W */
102 DWORD pi2_needed; /* size for PORT_INFO_2W */
103 DWORD returned; /* number of cached PORT_INFO_2W - entries */
104 } monitor_t;
106 typedef struct {
107 DWORD job_id;
108 HANDLE hf;
109 } started_doc_t;
111 typedef struct {
112 struct list jobs;
113 LONG ref;
114 } jobqueue_t;
116 typedef struct {
117 LPWSTR name;
118 jobqueue_t *queue;
119 started_doc_t *doc;
120 } opened_printer_t;
122 typedef struct {
123 struct list entry;
124 DWORD job_id;
125 WCHAR *filename;
126 WCHAR *document_title;
127 } job_t;
130 typedef struct {
131 LPCWSTR envname;
132 LPCWSTR subdir;
133 DWORD driverversion;
134 LPCWSTR versionregpath;
135 LPCWSTR versionsubdir;
136 } printenv_t;
138 /* ############################### */
140 static struct list monitor_handles = LIST_INIT( monitor_handles );
141 static monitor_t * pm_localport;
143 static opened_printer_t **printer_handles;
144 static int nb_printer_handles;
145 static LONG next_job_id = 1;
147 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
148 WORD fwCapability, LPSTR lpszOutput,
149 LPDEVMODEA lpdm );
150 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
151 LPSTR lpszDevice, LPSTR lpszPort,
152 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
153 DWORD fwMode );
155 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
156 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
157 'c','o','n','t','r','o','l','\\',
158 'P','r','i','n','t','\\',
159 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
160 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
162 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
163 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
164 'C','o','n','t','r','o','l','\\',
165 'P','r','i','n','t','\\',
166 'M','o','n','i','t','o','r','s','\\',0};
168 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
169 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
170 'C','o','n','t','r','o','l','\\',
171 'P','r','i','n','t','\\',
172 'P','r','i','n','t','e','r','s',0};
174 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
176 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
177 'M','i','c','r','o','s','o','f','t','\\',
178 'W','i','n','d','o','w','s',' ','N','T','\\',
179 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
180 'W','i','n','d','o','w','s',0};
182 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
183 'M','i','c','r','o','s','o','f','t','\\',
184 'W','i','n','d','o','w','s',' ','N','T','\\',
185 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
186 'D','e','v','i','c','e','s',0};
188 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
189 'M','i','c','r','o','s','o','f','t','\\',
190 'W','i','n','d','o','w','s',' ','N','T','\\',
191 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
192 'P','o','r','t','s',0};
194 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
195 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
196 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
197 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
198 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
199 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
200 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
202 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
203 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
205 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
206 'i','o','n',' ','F','i','l','e',0};
207 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
208 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
209 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
210 'M','o','d','e',0};
211 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
212 'i','l','e','s',0};
213 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
214 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
215 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
216 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
217 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
218 static const WCHAR NameW[] = {'N','a','m','e',0};
219 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
220 static const WCHAR PortW[] = {'P','o','r','t',0};
221 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
222 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
223 's','s','o','r',0};
224 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
225 'v','e','r',0};
226 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
227 'v','e','r','D','a','t','a',0};
228 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
229 'i','l','e',0};
230 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
231 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
232 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
233 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
234 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
235 static const WCHAR emptyStringW[] = {0};
237 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
239 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
240 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
241 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
243 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
244 'D','o','c','u','m','e','n','t',0};
246 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
247 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
248 DWORD Level, LPBYTE pDriverInfo,
249 DWORD cbBuf, LPDWORD pcbNeeded,
250 BOOL unicode);
251 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey);
252 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey);
254 /******************************************************************
255 * validate the user-supplied printing-environment [internal]
257 * PARAMS
258 * env [I] PTR to Environment-String or NULL
260 * RETURNS
261 * Failure: NULL
262 * Success: PTR to printenv_t
264 * NOTES
265 * An empty string is handled the same way as NULL.
266 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
270 static const printenv_t * validate_envW(LPCWSTR env)
272 static const printenv_t env_x86 = {envname_x86W, subdir_x86W,
273 3, Version3_RegPathW, Version3_SubdirW};
274 static const printenv_t env_win40 = {envname_win40W, subdir_win40W,
275 0, emptyStringW, emptyStringW};
276 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
278 const printenv_t *result = NULL;
279 unsigned int i;
281 TRACE("testing %s\n", debugstr_w(env));
282 if (env && env[0])
284 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
286 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
288 result = all_printenv[i];
289 break;
293 if (result == NULL) {
294 FIXME("unsupported Environment: %s\n", debugstr_w(env));
295 SetLastError(ERROR_INVALID_ENVIRONMENT);
297 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
299 else
301 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
303 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
305 return result;
309 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
310 if passed a NULL string. This returns NULLs to the result.
312 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
314 if ( (src) )
316 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
317 return usBufferPtr->Buffer;
319 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
320 return NULL;
323 static LPWSTR strdupW(LPCWSTR p)
325 LPWSTR ret;
326 DWORD len;
328 if(!p) return NULL;
329 len = (strlenW(p) + 1) * sizeof(WCHAR);
330 ret = HeapAlloc(GetProcessHeap(), 0, len);
331 memcpy(ret, p, len);
332 return ret;
335 static LPSTR strdupWtoA( LPCWSTR str )
337 LPSTR ret;
338 INT len;
340 if (!str) return NULL;
341 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
342 ret = HeapAlloc( GetProcessHeap(), 0, len );
343 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
344 return ret;
347 /* Returns the number of bytes in an ansi \0\0 terminated string (multi_sz).
348 The result includes all \0s (specifically the last two). */
349 static int multi_sz_lenA(const char *str)
351 const char *ptr = str;
352 if(!str) return 0;
355 ptr += lstrlenA(ptr) + 1;
356 } while(*ptr);
358 return ptr - str + 1;
361 static void
362 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
363 char qbuf[200];
365 /* If forcing, or no profile string entry for device yet, set the entry
367 * The always change entry if not WINEPS yet is discussable.
369 if (force ||
370 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
371 !strcmp(qbuf,"*") ||
372 !strstr(qbuf,"WINEPS.DRV")
374 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
375 HKEY hkey;
377 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
378 WriteProfileStringA("windows","device",buf);
379 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
380 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
381 RegCloseKey(hkey);
383 HeapFree(GetProcessHeap(),0,buf);
387 static BOOL add_printer_driver(char *name)
389 DRIVER_INFO_3A di3a;
391 static char driver_path[] = "wineps16",
392 data_file[] = "<datafile?>",
393 config_file[] = "wineps16",
394 help_file[] = "<helpfile?>",
395 dep_file[] = "<dependent files?>\0",
396 monitor_name[] = "<monitor name?>",
397 default_data_type[] = "RAW";
399 di3a.cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
400 di3a.pName = (char *)name;
401 di3a.pEnvironment = NULL; /* NULL means auto */
402 di3a.pDriverPath = driver_path;
403 di3a.pDataFile = data_file;
404 di3a.pConfigFile = config_file;
405 di3a.pHelpFile = help_file;
406 di3a.pDependentFiles = dep_file;
407 di3a.pMonitorName = monitor_name;
408 di3a.pDefaultDataType = default_data_type;
410 if (!AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a))
412 ERR("Failed adding driver (%d)\n", GetLastError());
413 return FALSE;
415 return TRUE;
418 #ifdef HAVE_CUPS_CUPS_H
419 static typeof(cupsGetDests) *pcupsGetDests;
420 static typeof(cupsGetPPD) *pcupsGetPPD;
421 static typeof(cupsPrintFile) *pcupsPrintFile;
422 static void *cupshandle;
424 static BOOL CUPS_LoadPrinters(void)
426 int i, nrofdests;
427 BOOL hadprinter = FALSE;
428 cups_dest_t *dests;
429 PRINTER_INFO_2A pinfo2a;
430 char *port,*devline;
431 HKEY hkeyPrinter, hkeyPrinters, hkey;
433 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
434 if (!cupshandle)
435 return FALSE;
436 TRACE("loaded %s\n", SONAME_LIBCUPS);
438 #define DYNCUPS(x) \
439 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
440 if (!p##x) return FALSE;
442 DYNCUPS(cupsGetPPD);
443 DYNCUPS(cupsGetDests);
444 DYNCUPS(cupsPrintFile);
445 #undef DYNCUPS
447 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
448 ERROR_SUCCESS) {
449 ERR("Can't create Printers key\n");
450 return FALSE;
453 nrofdests = pcupsGetDests(&dests);
454 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
455 for (i=0;i<nrofdests;i++) {
456 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
457 sprintf(port,"LPR:%s",dests[i].name);
458 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
459 sprintf(devline,"WINEPS.DRV,%s",port);
460 WriteProfileStringA("devices",dests[i].name,devline);
461 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
462 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
463 RegCloseKey(hkey);
465 HeapFree(GetProcessHeap(),0,devline);
467 TRACE("Printer %d: %s\n", i, dests[i].name);
468 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
469 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
470 and continue */
471 TRACE("Printer already exists\n");
472 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
473 RegCloseKey(hkeyPrinter);
474 } else {
475 static CHAR data_type[] = "RAW",
476 print_proc[] = "WinPrint",
477 comment[] = "WINEPS Printer using CUPS",
478 location[] = "<physical location of printer>",
479 params[] = "<parameters?>",
480 share_name[] = "<share name?>",
481 sep_file[] = "<sep file?>";
483 add_printer_driver(dests[i].name);
485 memset(&pinfo2a,0,sizeof(pinfo2a));
486 pinfo2a.pPrinterName = dests[i].name;
487 pinfo2a.pDatatype = data_type;
488 pinfo2a.pPrintProcessor = print_proc;
489 pinfo2a.pDriverName = dests[i].name;
490 pinfo2a.pComment = comment;
491 pinfo2a.pLocation = location;
492 pinfo2a.pPortName = port;
493 pinfo2a.pParameters = params;
494 pinfo2a.pShareName = share_name;
495 pinfo2a.pSepFile = sep_file;
497 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
498 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
499 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
502 HeapFree(GetProcessHeap(),0,port);
504 hadprinter = TRUE;
505 if (dests[i].is_default)
506 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
508 RegCloseKey(hkeyPrinters);
509 return hadprinter;
511 #endif
513 static BOOL
514 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
515 PRINTER_INFO_2A pinfo2a;
516 char *e,*s,*name,*prettyname,*devname;
517 BOOL ret = FALSE, set_default = FALSE;
518 char *port,*devline,*env_default;
519 HKEY hkeyPrinter, hkeyPrinters, hkey;
521 while (isspace(*pent)) pent++;
522 s = strchr(pent,':');
523 if(s) *s='\0';
524 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
525 strcpy(name,pent);
526 if(s) {
527 *s=':';
528 pent = s;
529 } else
530 pent = "";
532 TRACE("name=%s entry=%s\n",name, pent);
534 if(ispunct(*name)) { /* a tc entry, not a real printer */
535 TRACE("skipping tc entry\n");
536 goto end;
539 if(strstr(pent,":server")) { /* server only version so skip */
540 TRACE("skipping server entry\n");
541 goto end;
544 /* Determine whether this is a postscript printer. */
546 ret = TRUE;
547 env_default = getenv("PRINTER");
548 prettyname = name;
549 /* Get longest name, usually the one at the right for later display. */
550 while((s=strchr(prettyname,'|'))) {
551 *s = '\0';
552 e = s;
553 while(isspace(*--e)) *e = '\0';
554 TRACE("\t%s\n", debugstr_a(prettyname));
555 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
556 for(prettyname = s+1; isspace(*prettyname); prettyname++)
559 e = prettyname + strlen(prettyname);
560 while(isspace(*--e)) *e = '\0';
561 TRACE("\t%s\n", debugstr_a(prettyname));
562 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
564 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
565 * if it is too long, we use it as comment below. */
566 devname = prettyname;
567 if (strlen(devname)>=CCHDEVICENAME-1)
568 devname = name;
569 if (strlen(devname)>=CCHDEVICENAME-1) {
570 ret = FALSE;
571 goto end;
574 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
575 sprintf(port,"LPR:%s",name);
577 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
578 sprintf(devline,"WINEPS.DRV,%s",port);
579 WriteProfileStringA("devices",devname,devline);
580 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
581 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
582 RegCloseKey(hkey);
584 HeapFree(GetProcessHeap(),0,devline);
586 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
587 ERROR_SUCCESS) {
588 ERR("Can't create Printers key\n");
589 ret = FALSE;
590 goto end;
592 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
593 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
594 and continue */
595 TRACE("Printer already exists\n");
596 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
597 RegCloseKey(hkeyPrinter);
598 } else {
599 static CHAR data_type[] = "RAW",
600 print_proc[] = "WinPrint",
601 comment[] = "WINEPS Printer using LPR",
602 params[] = "<parameters?>",
603 share_name[] = "<share name?>",
604 sep_file[] = "<sep file?>";
606 add_printer_driver(devname);
608 memset(&pinfo2a,0,sizeof(pinfo2a));
609 pinfo2a.pPrinterName = devname;
610 pinfo2a.pDatatype = data_type;
611 pinfo2a.pPrintProcessor = print_proc;
612 pinfo2a.pDriverName = devname;
613 pinfo2a.pComment = comment;
614 pinfo2a.pLocation = prettyname;
615 pinfo2a.pPortName = port;
616 pinfo2a.pParameters = params;
617 pinfo2a.pShareName = share_name;
618 pinfo2a.pSepFile = sep_file;
620 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
621 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
622 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
625 RegCloseKey(hkeyPrinters);
627 if (isfirst || set_default)
628 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
630 HeapFree(GetProcessHeap(), 0, port);
631 end:
632 HeapFree(GetProcessHeap(), 0, name);
633 return ret;
636 static BOOL
637 PRINTCAP_LoadPrinters(void) {
638 BOOL hadprinter = FALSE;
639 char buf[200];
640 FILE *f;
641 char *pent = NULL;
642 BOOL had_bash = FALSE;
644 f = fopen("/etc/printcap","r");
645 if (!f)
646 return FALSE;
648 while(fgets(buf,sizeof(buf),f)) {
649 char *start, *end;
651 end=strchr(buf,'\n');
652 if (end) *end='\0';
654 start = buf;
655 while(isspace(*start)) start++;
656 if(*start == '#' || *start == '\0')
657 continue;
659 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
660 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
661 HeapFree(GetProcessHeap(),0,pent);
662 pent = NULL;
665 if (end && *--end == '\\') {
666 *end = '\0';
667 had_bash = TRUE;
668 } else
669 had_bash = FALSE;
671 if (pent) {
672 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
673 strcat(pent,start);
674 } else {
675 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
676 strcpy(pent,start);
680 if(pent) {
681 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
682 HeapFree(GetProcessHeap(),0,pent);
684 fclose(f);
685 return hadprinter;
688 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
690 if (value)
691 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
692 (lstrlenW(value) + 1) * sizeof(WCHAR));
693 else
694 return ERROR_FILE_NOT_FOUND;
697 void WINSPOOL_LoadSystemPrinters(void)
699 HKEY hkey, hkeyPrinters;
700 HANDLE hprn;
701 DWORD needed, num, i;
702 WCHAR PrinterName[256];
703 BOOL done = FALSE;
705 /* This ensures that all printer entries have a valid Name value. If causes
706 problems later if they don't. If one is found to be missed we create one
707 and set it equal to the name of the key */
708 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
709 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
710 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
711 for(i = 0; i < num; i++) {
712 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
713 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
714 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
715 set_reg_szW(hkey, NameW, PrinterName);
717 RegCloseKey(hkey);
722 RegCloseKey(hkeyPrinters);
725 /* We want to avoid calling AddPrinter on printers as much as
726 possible, because on cups printers this will (eventually) lead
727 to a call to cupsGetPPD which takes forever, even with non-cups
728 printers AddPrinter takes a while. So we'll tag all printers that
729 were automatically added last time around, if they still exist
730 we'll leave them be otherwise we'll delete them. */
731 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
732 if(needed) {
733 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
734 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
735 for(i = 0; i < num; i++) {
736 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
737 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
738 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
739 DWORD dw = 1;
740 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
741 RegCloseKey(hkey);
743 ClosePrinter(hprn);
748 HeapFree(GetProcessHeap(), 0, pi);
752 #ifdef HAVE_CUPS_CUPS_H
753 done = CUPS_LoadPrinters();
754 #endif
756 if(!done) { /* If we have any CUPS based printers, skip looking for printcap printers */
757 /* Check for [ppd] section in config file before parsing /etc/printcap */
758 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
759 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Printing\\PPD Files",
760 &hkey) == ERROR_SUCCESS) {
761 RegCloseKey(hkey);
762 PRINTCAP_LoadPrinters();
766 /* Now enumerate the list again and delete any printers that a still tagged */
767 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
768 if(needed) {
769 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
770 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
771 for(i = 0; i < num; i++) {
772 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
773 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
774 BOOL delete_driver = FALSE;
775 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
776 DWORD dw, type, size = sizeof(dw);
777 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
778 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
779 DeletePrinter(hprn);
780 delete_driver = TRUE;
782 RegCloseKey(hkey);
784 ClosePrinter(hprn);
785 if(delete_driver)
786 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
791 HeapFree(GetProcessHeap(), 0, pi);
794 return;
798 /*****************************************************************************
799 * enumerate the local monitors (INTERNAL)
801 * returns the needed size (in bytes) for pMonitors
802 * and *lpreturned is set to number of entries returned in pMonitors
805 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
807 HKEY hroot = NULL;
808 HKEY hentry = NULL;
809 LPWSTR ptr;
810 LPMONITOR_INFO_2W mi;
811 WCHAR buffer[MAX_PATH];
812 WCHAR dllname[MAX_PATH];
813 DWORD dllsize;
814 DWORD len;
815 DWORD index = 0;
816 DWORD needed = 0;
817 DWORD numentries;
818 DWORD entrysize;
820 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
822 numentries = *lpreturned; /* this is 0, when we scan the registry */
823 len = entrysize * numentries;
824 ptr = (LPWSTR) &pMonitors[len];
826 numentries = 0;
827 len = sizeof(buffer);
828 buffer[0] = '\0';
830 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
831 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
832 /* Scan all Monitor-Registry-Keys */
833 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
834 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
835 dllsize = sizeof(dllname);
836 dllname[0] = '\0';
838 /* The Monitor must have a Driver-DLL */
839 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
840 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
841 /* We found a valid DLL for this Monitor. */
842 TRACE("using Driver: %s\n", debugstr_w(dllname));
844 RegCloseKey(hentry);
847 /* Windows returns only Port-Monitors here, but to simplify our code,
848 we do no filtering for Language-Monitors */
849 if (dllname[0]) {
850 numentries++;
851 needed += entrysize;
852 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
853 if (level > 1) {
854 /* we install and return only monitors for "Windows NT x86" */
855 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
856 needed += dllsize;
859 /* required size is calculated. Now fill the user-buffer */
860 if (pMonitors && (cbBuf >= needed)){
861 mi = (LPMONITOR_INFO_2W) pMonitors;
862 pMonitors += entrysize;
864 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
865 mi->pName = ptr;
866 lstrcpyW(ptr, buffer); /* Name of the Monitor */
867 ptr += (len+1); /* len is lstrlenW(monitorname) */
868 if (level > 1) {
869 mi->pEnvironment = ptr;
870 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
871 ptr += (lstrlenW(envname_x86W)+1);
873 mi->pDLLName = ptr;
874 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
875 ptr += (dllsize / sizeof(WCHAR));
879 index++;
880 len = sizeof(buffer);
881 buffer[0] = '\0';
883 RegCloseKey(hroot);
885 *lpreturned = numentries;
886 TRACE("need %d byte for %d entries\n", needed, numentries);
887 return needed;
890 /******************************************************************
891 * monitor_flush [internal]
893 * flush the cached PORT_INFO_2W - data
896 void monitor_flush(monitor_t * pm)
898 if (!pm) return;
900 EnterCriticalSection(&monitor_handles_cs);
902 TRACE("%p (%s) cache: %p (%d, %d)\n", pm, debugstr_w(pm->name), pm->cache, pm->pi1_needed, pm->pi2_needed);
904 HeapFree(GetProcessHeap(), 0, pm->cache);
905 pm->cache = NULL;
906 pm->pi1_needed = 0;
907 pm->pi2_needed = 0;
908 pm->returned = 0;
909 LeaveCriticalSection(&monitor_handles_cs);
912 /******************************************************************
913 * monitor_unload [internal]
915 * release a printmonitor and unload it from memory, when needed
918 static void monitor_unload(monitor_t * pm)
920 if (pm == NULL) return;
921 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
923 EnterCriticalSection(&monitor_handles_cs);
925 if (pm->refcount) pm->refcount--;
927 if (pm->refcount == 0) {
928 list_remove(&pm->entry);
929 FreeLibrary(pm->hdll);
930 HeapFree(GetProcessHeap(), 0, pm->name);
931 HeapFree(GetProcessHeap(), 0, pm->dllname);
932 HeapFree(GetProcessHeap(), 0, pm);
934 LeaveCriticalSection(&monitor_handles_cs);
937 /******************************************************************
938 * monitor_unloadall [internal]
940 * release all printmonitors and unload them from memory, when needed
943 static void monitor_unloadall(void)
945 monitor_t * pm;
946 monitor_t * next;
948 EnterCriticalSection(&monitor_handles_cs);
949 /* iterate through the list, with safety against removal */
950 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
952 monitor_unload(pm);
954 LeaveCriticalSection(&monitor_handles_cs);
957 /******************************************************************
958 * monitor_load [internal]
960 * load a printmonitor, get the dllname from the registry, when needed
961 * initialize the monitor and dump found function-pointers
963 * On failure, SetLastError() is called and NULL is returned
966 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
968 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
969 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
970 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
971 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
972 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
974 monitor_t * pm = NULL;
975 monitor_t * cursor;
976 LPWSTR regroot = NULL;
977 LPWSTR driver = dllname;
979 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
980 /* Is the Monitor already loaded? */
981 EnterCriticalSection(&monitor_handles_cs);
983 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
985 if (lstrcmpW(name, cursor->name) == 0) {
986 pm = cursor;
987 break;
991 if (pm == NULL) {
992 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
993 if (pm == NULL) goto cleanup;
994 list_add_tail(&monitor_handles, &pm->entry);
996 pm->refcount++;
998 if (pm->name == NULL) {
999 /* Load the monitor */
1000 LPMONITOREX pmonitorEx;
1001 DWORD len;
1003 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
1004 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1006 if (regroot) {
1007 lstrcpyW(regroot, MonitorsW);
1008 lstrcatW(regroot, name);
1009 /* Get the Driver from the Registry */
1010 if (driver == NULL) {
1011 HKEY hroot;
1012 DWORD namesize;
1013 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
1014 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
1015 &namesize) == ERROR_SUCCESS) {
1016 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
1017 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
1019 RegCloseKey(hroot);
1024 pm->name = strdupW(name);
1025 pm->dllname = strdupW(driver);
1027 if (!regroot || !pm->name || !pm->dllname) {
1028 monitor_unload(pm);
1029 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1030 pm = NULL;
1031 goto cleanup;
1034 pm->hdll = LoadLibraryW(driver);
1035 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
1037 if (pm->hdll == NULL) {
1038 monitor_unload(pm);
1039 SetLastError(ERROR_MOD_NOT_FOUND);
1040 pm = NULL;
1041 goto cleanup;
1044 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
1045 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
1046 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
1047 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
1048 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
1051 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
1052 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
1053 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
1054 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
1055 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
1057 if (pInitializePrintMonitorUI != NULL) {
1058 pm->monitorUI = pInitializePrintMonitorUI();
1059 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
1060 if (pm->monitorUI) {
1061 TRACE( "0x%08x: dwMonitorSize (%d)\n",
1062 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
1067 if (pInitializePrintMonitor != NULL) {
1068 pmonitorEx = pInitializePrintMonitor(regroot);
1069 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
1070 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
1072 if (pmonitorEx) {
1073 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
1074 pm->monitor = &(pmonitorEx->Monitor);
1078 if (pm->monitor) {
1079 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
1083 if (!pm->monitor) {
1084 if (pInitializePrintMonitor2 != NULL) {
1085 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
1087 if (pInitializeMonitorEx != NULL) {
1088 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
1090 if (pInitializeMonitor != NULL) {
1091 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
1094 if (!pm->monitor && !pm->monitorUI) {
1095 monitor_unload(pm);
1096 SetLastError(ERROR_PROC_NOT_FOUND);
1097 pm = NULL;
1100 cleanup:
1101 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
1102 pm->refcount++;
1103 pm_localport = pm;
1105 LeaveCriticalSection(&monitor_handles_cs);
1106 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
1107 HeapFree(GetProcessHeap(), 0, regroot);
1108 TRACE("=> %p\n", pm);
1109 return pm;
1112 /******************************************************************
1113 * monitor_loadall [internal]
1115 * Load all registered monitors
1118 static DWORD monitor_loadall(void)
1120 monitor_t * pm;
1121 DWORD registered = 0;
1122 DWORD loaded = 0;
1123 HKEY hmonitors;
1124 WCHAR buffer[MAX_PATH];
1125 DWORD id = 0;
1127 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hmonitors) == ERROR_SUCCESS) {
1128 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
1129 NULL, NULL, NULL, NULL, NULL);
1131 TRACE("%d monitors registered\n", registered);
1133 EnterCriticalSection(&monitor_handles_cs);
1134 while (id < registered) {
1135 buffer[0] = '\0';
1136 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
1137 pm = monitor_load(buffer, NULL);
1138 if (pm) loaded++;
1139 id++;
1141 LeaveCriticalSection(&monitor_handles_cs);
1142 RegCloseKey(hmonitors);
1144 TRACE("%d monitors loaded\n", loaded);
1145 return loaded;
1148 /******************************************************************
1149 * monitor_load_by_port [internal]
1151 * load a printmonitor for a given port
1153 * On failure, NULL is returned
1156 static monitor_t * monitor_load_by_port(LPWSTR portname)
1158 HKEY hroot;
1159 HKEY hport;
1160 LPWSTR buffer;
1161 monitor_t * pm = NULL;
1162 DWORD registered = 0;
1163 DWORD id = 0;
1164 DWORD len;
1166 TRACE("(%s)\n", debugstr_w(portname));
1168 /* Try the Local Monitor first */
1169 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1170 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1171 /* found the portname */
1172 RegCloseKey(hroot);
1173 return monitor_load(LocalPortW, NULL);
1175 RegCloseKey(hroot);
1178 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1179 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1180 if (buffer == NULL) return NULL;
1182 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1183 EnterCriticalSection(&monitor_handles_cs);
1184 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1186 while ((pm == NULL) && (id < registered)) {
1187 buffer[0] = '\0';
1188 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1189 TRACE("testing %s\n", debugstr_w(buffer));
1190 len = lstrlenW(buffer);
1191 lstrcatW(buffer, bs_Ports_bsW);
1192 lstrcatW(buffer, portname);
1193 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1194 RegCloseKey(hport);
1195 buffer[len] = '\0'; /* use only the Monitor-Name */
1196 pm = monitor_load(buffer, NULL);
1198 id++;
1200 LeaveCriticalSection(&monitor_handles_cs);
1201 RegCloseKey(hroot);
1203 HeapFree(GetProcessHeap(), 0, buffer);
1204 return pm;
1207 /******************************************************************
1208 * enumerate the local Ports from all loaded monitors (internal)
1210 * returns the needed size (in bytes) for pPorts
1211 * and *lpreturned is set to number of entries returned in pPorts
1214 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
1216 monitor_t * pm;
1217 LPWSTR ptr;
1218 LPPORT_INFO_2W cache;
1219 LPPORT_INFO_2W out;
1220 DWORD res;
1221 DWORD cacheindex;
1222 DWORD outindex = 0;
1223 DWORD needed = 0;
1224 DWORD numentries;
1225 DWORD entrysize;
1228 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
1229 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
1231 numentries = *lpreturned; /* this is 0, when we scan the registry */
1232 needed = entrysize * numentries;
1233 ptr = (LPWSTR) &pPorts[needed];
1235 numentries = 0;
1236 needed = 0;
1238 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1240 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
1241 if (pm->cache == NULL) {
1242 res = pm->monitor->pfnEnumPorts(NULL, 2, NULL, 0, &(pm->pi2_needed), &(pm->returned));
1243 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
1244 pm->cache = HeapAlloc(GetProcessHeap(), 0, (pm->pi2_needed));
1245 res = pm->monitor->pfnEnumPorts(NULL, 2, (LPBYTE) pm->cache, pm->pi2_needed, &(pm->pi2_needed), &(pm->returned));
1247 TRACE("(%s) got %d with %d (cache need %d byte for %d entries)\n",
1248 debugstr_w(pm->name), res, GetLastError(), pm->pi2_needed, pm->returned);
1249 res = FALSE;
1251 if (pm->cache && (level == 1) && (pm->pi1_needed == 0) && (pm->returned > 0)) {
1252 cacheindex = 0;
1253 cache = pm->cache;
1254 while (cacheindex < (pm->returned)) {
1255 pm->pi1_needed += sizeof(PORT_INFO_1W);
1256 pm->pi1_needed += (lstrlenW(cache->pPortName) + 1) * sizeof(WCHAR);
1257 cache++;
1258 cacheindex++;
1260 TRACE("%d byte for %d cached PORT_INFO_1W entries (%s)\n",
1261 pm->pi1_needed, cacheindex, debugstr_w(pm->name));
1263 numentries += pm->returned;
1264 needed += (level == 1) ? pm->pi1_needed : pm->pi2_needed;
1266 /* fill the buffer, if we have one */
1267 if (pPorts && (cbBuf >= needed )) {
1268 cacheindex = 0;
1269 cache = pm->cache;
1270 while (cacheindex < pm->returned) {
1271 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
1272 out->pPortName = ptr;
1273 lstrcpyW(ptr, cache->pPortName);
1274 ptr += (lstrlenW(ptr)+1);
1275 if (level > 1) {
1276 out->pMonitorName = ptr;
1277 lstrcpyW(ptr, cache->pMonitorName);
1278 ptr += (lstrlenW(ptr)+1);
1280 out->pDescription = ptr;
1281 lstrcpyW(ptr, cache->pDescription);
1282 ptr += (lstrlenW(ptr)+1);
1283 out->fPortType = cache->fPortType;
1284 out->Reserved = cache->Reserved;
1286 cache++;
1287 cacheindex++;
1288 outindex++;
1294 *lpreturned = numentries;
1295 TRACE("need %d byte for %d entries\n", needed, numentries);
1296 return needed;
1299 /******************************************************************
1300 * get_opened_printer_entry
1301 * Get the first place empty in the opened printer table
1303 * ToDo:
1304 * - pDefault is ignored
1306 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1308 UINT_PTR handle = nb_printer_handles, i;
1309 jobqueue_t *queue = NULL;
1310 opened_printer_t *printer = NULL;
1312 EnterCriticalSection(&printer_handles_cs);
1314 for (i = 0; i < nb_printer_handles; i++)
1316 if (!printer_handles[i])
1318 if(handle == nb_printer_handles)
1319 handle = i;
1321 else
1323 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1324 queue = printer_handles[i]->queue;
1328 if (handle >= nb_printer_handles)
1330 opened_printer_t **new_array;
1331 if (printer_handles)
1332 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1333 (nb_printer_handles + 16) * sizeof(*new_array) );
1334 else
1335 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1336 (nb_printer_handles + 16) * sizeof(*new_array) );
1338 if (!new_array)
1340 handle = 0;
1341 goto end;
1343 printer_handles = new_array;
1344 nb_printer_handles += 16;
1347 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1349 handle = 0;
1350 goto end;
1353 if(name) {
1354 printer->name = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
1355 if (!printer->name) {
1356 handle = 0;
1357 goto end;
1359 strcpyW(printer->name, name);
1362 if(queue)
1363 printer->queue = queue;
1364 else
1366 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1367 if (!printer->queue) {
1368 handle = 0;
1369 goto end;
1371 list_init(&printer->queue->jobs);
1372 printer->queue->ref = 0;
1374 InterlockedIncrement(&printer->queue->ref);
1376 printer_handles[handle] = printer;
1377 handle++;
1378 end:
1379 LeaveCriticalSection(&printer_handles_cs);
1380 if (!handle && printer) {
1381 /* Something Failed: Free the Buffers */
1382 HeapFree(GetProcessHeap(), 0, printer->name);
1383 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1384 HeapFree(GetProcessHeap(), 0, printer);
1387 return (HANDLE)handle;
1390 /******************************************************************
1391 * get_opened_printer
1392 * Get the pointer to the opened printer referred by the handle
1394 static opened_printer_t *get_opened_printer(HANDLE hprn)
1396 UINT_PTR idx = (UINT_PTR)hprn;
1397 opened_printer_t *ret = NULL;
1399 EnterCriticalSection(&printer_handles_cs);
1401 if ((idx <= 0) || (idx > nb_printer_handles))
1402 goto end;
1404 ret = printer_handles[idx - 1];
1405 end:
1406 LeaveCriticalSection(&printer_handles_cs);
1407 return ret;
1410 /******************************************************************
1411 * get_opened_printer_name
1412 * Get the pointer to the opened printer name referred by the handle
1414 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1416 opened_printer_t *printer = get_opened_printer(hprn);
1417 if(!printer) return NULL;
1418 return printer->name;
1421 /******************************************************************
1422 * WINSPOOL_GetOpenedPrinterRegKey
1425 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1427 LPCWSTR name = get_opened_printer_name(hPrinter);
1428 DWORD ret;
1429 HKEY hkeyPrinters;
1431 if(!name) return ERROR_INVALID_HANDLE;
1433 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1434 ERROR_SUCCESS)
1435 return ret;
1437 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1439 ERR("Can't find opened printer %s in registry\n",
1440 debugstr_w(name));
1441 RegCloseKey(hkeyPrinters);
1442 return ERROR_INVALID_PRINTER_NAME; /* ? */
1444 RegCloseKey(hkeyPrinters);
1445 return ERROR_SUCCESS;
1448 /******************************************************************
1449 * get_job
1451 * Get the pointer to the specified job.
1452 * Should hold the printer_handles_cs before calling.
1454 static job_t *get_job(HANDLE hprn, DWORD JobId)
1456 opened_printer_t *printer = get_opened_printer(hprn);
1457 job_t *job;
1459 if(!printer) return NULL;
1460 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1462 if(job->job_id == JobId)
1463 return job;
1465 return NULL;
1468 /***********************************************************
1469 * DEVMODEcpyAtoW
1471 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1473 BOOL Formname;
1474 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1475 DWORD size;
1477 Formname = (dmA->dmSize > off_formname);
1478 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1479 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1480 dmW->dmDeviceName, CCHDEVICENAME);
1481 if(!Formname) {
1482 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1483 dmA->dmSize - CCHDEVICENAME);
1484 } else {
1485 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1486 off_formname - CCHDEVICENAME);
1487 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1488 dmW->dmFormName, CCHFORMNAME);
1489 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1490 (off_formname + CCHFORMNAME));
1492 dmW->dmSize = size;
1493 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1494 dmA->dmDriverExtra);
1495 return dmW;
1498 /***********************************************************
1499 * DEVMODEdupWtoA
1500 * Creates an ascii copy of supplied devmode on heap
1502 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
1504 LPDEVMODEA dmA;
1505 DWORD size;
1506 BOOL Formname;
1507 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
1509 if(!dmW) return NULL;
1510 Formname = (dmW->dmSize > off_formname);
1511 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
1512 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1513 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1514 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1515 if(!Formname) {
1516 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1517 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
1518 } else {
1519 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1520 off_formname - CCHDEVICENAME * sizeof(WCHAR));
1521 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1522 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1523 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
1524 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
1526 dmA->dmSize = size;
1527 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
1528 dmW->dmDriverExtra);
1529 return dmA;
1532 /***********************************************************
1533 * PRINTER_INFO_2AtoW
1534 * Creates a unicode copy of PRINTER_INFO_2A on heap
1536 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1538 LPPRINTER_INFO_2W piW;
1539 UNICODE_STRING usBuffer;
1541 if(!piA) return NULL;
1542 piW = HeapAlloc(heap, 0, sizeof(*piW));
1543 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1545 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1546 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1547 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1548 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1549 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1550 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1551 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1552 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1553 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1554 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1555 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1556 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1557 return piW;
1560 /***********************************************************
1561 * FREE_PRINTER_INFO_2W
1562 * Free PRINTER_INFO_2W and all strings
1564 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1566 if(!piW) return;
1568 HeapFree(heap,0,piW->pServerName);
1569 HeapFree(heap,0,piW->pPrinterName);
1570 HeapFree(heap,0,piW->pShareName);
1571 HeapFree(heap,0,piW->pPortName);
1572 HeapFree(heap,0,piW->pDriverName);
1573 HeapFree(heap,0,piW->pComment);
1574 HeapFree(heap,0,piW->pLocation);
1575 HeapFree(heap,0,piW->pDevMode);
1576 HeapFree(heap,0,piW->pSepFile);
1577 HeapFree(heap,0,piW->pPrintProcessor);
1578 HeapFree(heap,0,piW->pDatatype);
1579 HeapFree(heap,0,piW->pParameters);
1580 HeapFree(heap,0,piW);
1581 return;
1584 /******************************************************************
1585 * DeviceCapabilities [WINSPOOL.@]
1586 * DeviceCapabilitiesA [WINSPOOL.@]
1589 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1590 LPSTR pOutput, LPDEVMODEA lpdm)
1592 INT ret;
1594 if (!GDI_CallDeviceCapabilities16)
1596 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1597 (LPCSTR)104 );
1598 if (!GDI_CallDeviceCapabilities16) return -1;
1600 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1602 /* If DC_PAPERSIZE map POINT16s to POINTs */
1603 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1604 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1605 POINT *pt = (POINT *)pOutput;
1606 INT i;
1607 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1608 for(i = 0; i < ret; i++, pt++)
1610 pt->x = tmp[i].x;
1611 pt->y = tmp[i].y;
1613 HeapFree( GetProcessHeap(), 0, tmp );
1615 return ret;
1619 /*****************************************************************************
1620 * DeviceCapabilitiesW [WINSPOOL.@]
1622 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1625 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1626 WORD fwCapability, LPWSTR pOutput,
1627 const DEVMODEW *pDevMode)
1629 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
1630 LPSTR pDeviceA = strdupWtoA(pDevice);
1631 LPSTR pPortA = strdupWtoA(pPort);
1632 INT ret;
1634 if(pOutput && (fwCapability == DC_BINNAMES ||
1635 fwCapability == DC_FILEDEPENDENCIES ||
1636 fwCapability == DC_PAPERNAMES)) {
1637 /* These need A -> W translation */
1638 INT size = 0, i;
1639 LPSTR pOutputA;
1640 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1641 dmA);
1642 if(ret == -1)
1643 return ret;
1644 switch(fwCapability) {
1645 case DC_BINNAMES:
1646 size = 24;
1647 break;
1648 case DC_PAPERNAMES:
1649 case DC_FILEDEPENDENCIES:
1650 size = 64;
1651 break;
1653 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1654 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1655 dmA);
1656 for(i = 0; i < ret; i++)
1657 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1658 pOutput + (i * size), size);
1659 HeapFree(GetProcessHeap(), 0, pOutputA);
1660 } else {
1661 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1662 (LPSTR)pOutput, dmA);
1664 HeapFree(GetProcessHeap(),0,pPortA);
1665 HeapFree(GetProcessHeap(),0,pDeviceA);
1666 HeapFree(GetProcessHeap(),0,dmA);
1667 return ret;
1670 /******************************************************************
1671 * DocumentPropertiesA [WINSPOOL.@]
1673 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1675 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1676 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1677 LPDEVMODEA pDevModeInput,DWORD fMode )
1679 LPSTR lpName = pDeviceName;
1680 static CHAR port[] = "LPT1:";
1681 LONG ret;
1683 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1684 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1687 if(!pDeviceName) {
1688 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1689 if(!lpNameW) {
1690 ERR("no name from hPrinter?\n");
1691 SetLastError(ERROR_INVALID_HANDLE);
1692 return -1;
1694 lpName = strdupWtoA(lpNameW);
1697 if (!GDI_CallExtDeviceMode16)
1699 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1700 (LPCSTR)102 );
1701 if (!GDI_CallExtDeviceMode16) {
1702 ERR("No CallExtDeviceMode16?\n");
1703 return -1;
1706 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1707 pDevModeInput, NULL, fMode);
1709 if(!pDeviceName)
1710 HeapFree(GetProcessHeap(),0,lpName);
1711 return ret;
1715 /*****************************************************************************
1716 * DocumentPropertiesW (WINSPOOL.@)
1718 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1720 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1721 LPWSTR pDeviceName,
1722 LPDEVMODEW pDevModeOutput,
1723 LPDEVMODEW pDevModeInput, DWORD fMode)
1726 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1727 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1728 LPDEVMODEA pDevModeOutputA = NULL;
1729 LONG ret;
1731 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1732 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1733 fMode);
1734 if(pDevModeOutput) {
1735 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1736 if(ret < 0) return ret;
1737 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1739 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1740 pDevModeInputA, fMode);
1741 if(pDevModeOutput) {
1742 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1743 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1745 if(fMode == 0 && ret > 0)
1746 ret += (CCHDEVICENAME + CCHFORMNAME);
1747 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1748 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1749 return ret;
1752 /******************************************************************
1753 * OpenPrinterA [WINSPOOL.@]
1755 * See OpenPrinterW.
1758 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1759 LPPRINTER_DEFAULTSA pDefault)
1761 UNICODE_STRING lpPrinterNameW;
1762 UNICODE_STRING usBuffer;
1763 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1764 PWSTR pwstrPrinterNameW;
1765 BOOL ret;
1767 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1769 if(pDefault) {
1770 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1771 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1772 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1773 pDefaultW = &DefaultW;
1775 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1776 if(pDefault) {
1777 RtlFreeUnicodeString(&usBuffer);
1778 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1780 RtlFreeUnicodeString(&lpPrinterNameW);
1781 return ret;
1784 /******************************************************************
1785 * OpenPrinterW [WINSPOOL.@]
1787 * Open a Printer / Printserver or a Printer-Object
1789 * PARAMS
1790 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1791 * phPrinter [O] The resulting Handle is stored here
1792 * pDefault [I] PTR to Default Printer Settings or NULL
1794 * RETURNS
1795 * Success: TRUE
1796 * Failure: FALSE
1798 * NOTES
1799 * lpPrinterName is one of:
1800 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1801 *| Printer: "PrinterName"
1802 *| Printer-Object: "PrinterName,Job xxx"
1803 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1804 *| XcvPort: "Servername,XcvPort PortName"
1806 * BUGS
1807 *| Printer-Object not supported
1808 *| XcvMonitor not supported
1809 *| XcvPort not supported
1810 *| pDefaults is ignored
1813 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1815 HKEY hkeyPrinters = NULL;
1816 HKEY hkeyPrinter = NULL;
1818 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1819 if (pDefault) {
1820 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1821 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1824 if(lpPrinterName != NULL)
1826 /* Check any Printer exists */
1827 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1828 ERR("Can't create Printers key\n");
1829 SetLastError(ERROR_FILE_NOT_FOUND);
1830 return FALSE;
1832 if((lpPrinterName[0] == '\0') || /* explicitly exclude "" */
1833 (RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter) != ERROR_SUCCESS)) {
1835 WARN("Printer not found in Registry: '%s'\n", debugstr_w(lpPrinterName));
1836 RegCloseKey(hkeyPrinters);
1837 SetLastError(ERROR_INVALID_PRINTER_NAME);
1838 return FALSE;
1840 RegCloseKey(hkeyPrinter);
1841 RegCloseKey(hkeyPrinters);
1843 if(!phPrinter) {
1844 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1845 SetLastError(ERROR_INVALID_PARAMETER);
1846 return FALSE;
1849 /* Get the unique handle of the printer or Printserver */
1850 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1851 return (*phPrinter != 0);
1854 /******************************************************************
1855 * AddMonitorA [WINSPOOL.@]
1857 * See AddMonitorW.
1860 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1862 LPWSTR nameW = NULL;
1863 INT len;
1864 BOOL res;
1865 LPMONITOR_INFO_2A mi2a;
1866 MONITOR_INFO_2W mi2w;
1868 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1869 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1870 mi2a ? debugstr_a(mi2a->pName) : NULL,
1871 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
1872 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
1874 if (Level != 2) {
1875 SetLastError(ERROR_INVALID_LEVEL);
1876 return FALSE;
1879 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1880 if (mi2a == NULL) {
1881 return FALSE;
1884 if (pName) {
1885 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1886 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1887 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1890 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1891 if (mi2a->pName) {
1892 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1893 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1894 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1896 if (mi2a->pEnvironment) {
1897 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1898 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1899 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1901 if (mi2a->pDLLName) {
1902 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1903 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1904 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1907 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1909 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1910 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1911 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1913 HeapFree(GetProcessHeap(), 0, nameW);
1914 return (res);
1917 /******************************************************************************
1918 * AddMonitorW [WINSPOOL.@]
1920 * Install a Printmonitor
1922 * PARAMS
1923 * pName [I] Servername or NULL (local Computer)
1924 * Level [I] Structure-Level (Must be 2)
1925 * pMonitors [I] PTR to MONITOR_INFO_2
1927 * RETURNS
1928 * Success: TRUE
1929 * Failure: FALSE
1931 * NOTES
1932 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1935 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1937 monitor_t * pm = NULL;
1938 LPMONITOR_INFO_2W mi2w;
1939 HKEY hroot = NULL;
1940 HKEY hentry = NULL;
1941 DWORD disposition;
1942 BOOL res = FALSE;
1944 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1945 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1946 mi2w ? debugstr_w(mi2w->pName) : NULL,
1947 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
1948 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
1950 if (Level != 2) {
1951 SetLastError(ERROR_INVALID_LEVEL);
1952 return FALSE;
1955 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1956 if (mi2w == NULL) {
1957 return FALSE;
1960 if (pName && (pName[0])) {
1961 FIXME("for server %s not implemented\n", debugstr_w(pName));
1962 SetLastError(ERROR_ACCESS_DENIED);
1963 return FALSE;
1967 if (!mi2w->pName || (! mi2w->pName[0])) {
1968 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
1969 SetLastError(ERROR_INVALID_PARAMETER);
1970 return FALSE;
1972 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
1973 WARN("Environment %s requested (we support only %s)\n",
1974 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
1975 SetLastError(ERROR_INVALID_ENVIRONMENT);
1976 return FALSE;
1979 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
1980 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
1981 SetLastError(ERROR_INVALID_PARAMETER);
1982 return FALSE;
1985 /* Load and initialize the monitor. SetLastError() is called on failure */
1986 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
1987 return FALSE;
1989 monitor_unload(pm);
1991 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
1992 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
1993 return FALSE;
1996 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1997 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
1998 &disposition) == ERROR_SUCCESS) {
2000 /* Some installers set options for the port before calling AddMonitor.
2001 We query the "Driver" entry to verify that the monitor is installed,
2002 before we return an error.
2003 When a user installs two print monitors at the same time with the
2004 same name but with a different driver DLL and a task switch comes
2005 between RegQueryValueExW and RegSetValueExW, a race condition
2006 is possible but silently ignored. */
2008 DWORD namesize = 0;
2010 if ((disposition == REG_OPENED_EXISTING_KEY) &&
2011 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
2012 &namesize) == ERROR_SUCCESS)) {
2013 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
2014 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2015 9x: ERROR_ALREADY_EXISTS (183) */
2016 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
2018 else
2020 INT len;
2021 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
2022 res = (RegSetValueExW(hentry, DriverW, 0,
2023 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
2025 RegCloseKey(hentry);
2028 RegCloseKey(hroot);
2029 return (res);
2032 /******************************************************************
2033 * DeletePrinterDriverA [WINSPOOL.@]
2036 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2038 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2041 /******************************************************************
2042 * DeletePrinterDriverW [WINSPOOL.@]
2045 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2047 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2050 /******************************************************************
2051 * DeleteMonitorA [WINSPOOL.@]
2053 * See DeleteMonitorW.
2056 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2058 LPWSTR nameW = NULL;
2059 LPWSTR EnvironmentW = NULL;
2060 LPWSTR MonitorNameW = NULL;
2061 BOOL res;
2062 INT len;
2064 if (pName) {
2065 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2066 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2067 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2070 if (pEnvironment) {
2071 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2072 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2073 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2075 if (pMonitorName) {
2076 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2077 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2078 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2081 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2083 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2084 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2085 HeapFree(GetProcessHeap(), 0, nameW);
2086 return (res);
2089 /******************************************************************
2090 * DeleteMonitorW [WINSPOOL.@]
2092 * Delete a specific Printmonitor from a Printing-Environment
2094 * PARAMS
2095 * pName [I] Servername or NULL (local Computer)
2096 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2097 * pMonitorName [I] Name of the Monitor, that should be deleted
2099 * RETURNS
2100 * Success: TRUE
2101 * Failure: FALSE
2103 * NOTES
2104 * pEnvironment is ignored in Windows for the local Computer.
2108 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2110 HKEY hroot = NULL;
2112 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2113 debugstr_w(pMonitorName));
2115 if (pName && (pName[0])) {
2116 FIXME("for server %s not implemented\n", debugstr_w(pName));
2117 SetLastError(ERROR_ACCESS_DENIED);
2118 return FALSE;
2121 /* pEnvironment is ignored in Windows for the local Computer */
2123 if (!pMonitorName || !pMonitorName[0]) {
2124 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
2125 SetLastError(ERROR_INVALID_PARAMETER);
2126 return FALSE;
2129 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2130 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2131 return FALSE;
2134 /* change this, when advapi32.dll/RegDeleteTree is implemented */
2135 if(WINSPOOL_SHDeleteKeyW(hroot, pMonitorName) == ERROR_SUCCESS) {
2136 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
2137 RegCloseKey(hroot);
2138 return TRUE;
2141 WARN("monitor %s does not exists\n", debugstr_w(pMonitorName));
2142 RegCloseKey(hroot);
2144 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2145 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
2146 return (FALSE);
2149 /******************************************************************
2150 * DeletePortA [WINSPOOL.@]
2152 * See DeletePortW.
2155 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2157 LPWSTR nameW = NULL;
2158 LPWSTR portW = NULL;
2159 INT len;
2160 DWORD res;
2162 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2164 /* convert servername to unicode */
2165 if (pName) {
2166 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2167 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2168 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2171 /* convert portname to unicode */
2172 if (pPortName) {
2173 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2174 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2175 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2178 res = DeletePortW(nameW, hWnd, portW);
2179 HeapFree(GetProcessHeap(), 0, nameW);
2180 HeapFree(GetProcessHeap(), 0, portW);
2181 return res;
2184 /******************************************************************
2185 * DeletePortW [WINSPOOL.@]
2187 * Delete a specific Port
2189 * PARAMS
2190 * pName [I] Servername or NULL (local Computer)
2191 * hWnd [I] Handle to parent Window for the Dialog-Box
2192 * pPortName [I] Name of the Port, that should be deleted
2194 * RETURNS
2195 * Success: TRUE
2196 * Failure: FALSE
2199 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2201 monitor_t * pm;
2202 DWORD res = ROUTER_UNKNOWN;
2204 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2206 if (pName && pName[0]) {
2207 SetLastError(ERROR_INVALID_PARAMETER);
2208 return FALSE;
2211 if (!pPortName) {
2212 SetLastError(RPC_X_NULL_REF_POINTER);
2213 return FALSE;
2216 /* an empty Portname is Invalid */
2217 if (!pPortName[0]) goto cleanup;
2219 pm = monitor_load_by_port(pPortName);
2220 if (pm && pm->monitor) {
2221 if (pm->monitor->pfnDeletePort != NULL) {
2222 TRACE("Using %s for %s:\n", debugstr_w(pm->name), debugstr_w(pPortName));
2223 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2224 TRACE("got %d with %d\n", res, GetLastError());
2226 else if (pm->monitor->pfnXcvOpenPort)
2228 FIXME("XcvOpenPort not implemented (dwMonitorSize: %d)\n", pm->dwMonitorSize);
2230 /* invalidate cached PORT_INFO_2W */
2231 if (res == ROUTER_SUCCESS) monitor_flush(pm);
2233 monitor_unload(pm);
2235 cleanup:
2236 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2237 if (res == ROUTER_UNKNOWN) SetLastError(ERROR_NOT_SUPPORTED);
2238 TRACE("returning %d with %d\n", (res == ROUTER_SUCCESS), GetLastError());
2239 return (res == ROUTER_SUCCESS);
2242 /******************************************************************************
2243 * SetPrinterW [WINSPOOL.@]
2245 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2247 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2248 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2249 return FALSE;
2252 /******************************************************************************
2253 * WritePrinter [WINSPOOL.@]
2255 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2257 opened_printer_t *printer;
2258 BOOL ret = FALSE;
2260 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2262 EnterCriticalSection(&printer_handles_cs);
2263 printer = get_opened_printer(hPrinter);
2264 if(!printer)
2266 SetLastError(ERROR_INVALID_HANDLE);
2267 goto end;
2270 if(!printer->doc)
2272 SetLastError(ERROR_SPL_NO_STARTDOC);
2273 goto end;
2276 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2277 end:
2278 LeaveCriticalSection(&printer_handles_cs);
2279 return ret;
2282 /*****************************************************************************
2283 * AddFormA [WINSPOOL.@]
2285 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2287 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2288 return 1;
2291 /*****************************************************************************
2292 * AddFormW [WINSPOOL.@]
2294 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2296 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2297 return 1;
2300 /*****************************************************************************
2301 * AddJobA [WINSPOOL.@]
2303 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2305 BOOL ret;
2306 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2307 DWORD needed;
2309 if(Level != 1) {
2310 SetLastError(ERROR_INVALID_LEVEL);
2311 return FALSE;
2314 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2316 if(ret) {
2317 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2318 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2319 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2320 if(*pcbNeeded > cbBuf) {
2321 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2322 ret = FALSE;
2323 } else {
2324 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2325 addjobA->JobId = addjobW->JobId;
2326 addjobA->Path = (char *)(addjobA + 1);
2327 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2330 return ret;
2333 /*****************************************************************************
2334 * AddJobW [WINSPOOL.@]
2336 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2338 opened_printer_t *printer;
2339 job_t *job;
2340 BOOL ret = FALSE;
2341 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2342 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2343 WCHAR path[MAX_PATH], filename[MAX_PATH];
2344 DWORD len;
2345 ADDJOB_INFO_1W *addjob;
2347 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2349 EnterCriticalSection(&printer_handles_cs);
2351 printer = get_opened_printer(hPrinter);
2353 if(!printer) {
2354 SetLastError(ERROR_INVALID_HANDLE);
2355 goto end;
2358 if(Level != 1) {
2359 SetLastError(ERROR_INVALID_LEVEL);
2360 goto end;
2363 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2364 if(!job)
2365 goto end;
2367 job->job_id = InterlockedIncrement(&next_job_id);
2369 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2370 if(path[len - 1] != '\\')
2371 path[len++] = '\\';
2372 memcpy(path + len, spool_path, sizeof(spool_path));
2373 sprintfW(filename, fmtW, path, job->job_id);
2375 len = strlenW(filename);
2376 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2377 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2378 job->document_title = strdupW(default_doc_title);
2379 list_add_tail(&printer->queue->jobs, &job->entry);
2381 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2382 if(*pcbNeeded <= cbBuf) {
2383 addjob = (ADDJOB_INFO_1W*)pData;
2384 addjob->JobId = job->job_id;
2385 addjob->Path = (WCHAR *)(addjob + 1);
2386 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2387 ret = TRUE;
2388 } else
2389 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2391 end:
2392 LeaveCriticalSection(&printer_handles_cs);
2393 return ret;
2396 /*****************************************************************************
2397 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2399 * Return the PATH for the Print-Processors
2401 * See GetPrintProcessorDirectoryW.
2405 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2406 DWORD level, LPBYTE Info,
2407 DWORD cbBuf, LPDWORD pcbNeeded)
2409 LPWSTR serverW = NULL;
2410 LPWSTR envW = NULL;
2411 BOOL ret;
2412 INT len;
2414 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2415 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2418 if (server) {
2419 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2420 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2421 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2424 if (env) {
2425 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2426 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2427 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2430 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2431 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2433 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2434 cbBuf, pcbNeeded);
2436 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2437 cbBuf, NULL, NULL) > 0;
2440 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2441 HeapFree(GetProcessHeap(), 0, envW);
2442 HeapFree(GetProcessHeap(), 0, serverW);
2443 return ret;
2446 /*****************************************************************************
2447 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2449 * Return the PATH for the Print-Processors
2451 * PARAMS
2452 * server [I] Servername (NT only) or NULL (local Computer)
2453 * env [I] Printing-Environment (see below) or NULL (Default)
2454 * level [I] Structure-Level (must be 1)
2455 * Info [O] PTR to Buffer that receives the Result
2456 * cbBuf [I] Size of Buffer at "Info"
2457 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2458 * required for the Buffer at "Info"
2460 * RETURNS
2461 * Success: TRUE and in pcbNeeded the Bytes used in Info
2462 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2463 * if cbBuf is too small
2465 * Native Values returned in Info on Success:
2466 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2467 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2468 *| win9x(Windows 4.0): "%winsysdir%"
2470 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2472 * BUGS
2473 * Only NULL or "" is supported for server
2476 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2477 DWORD level, LPBYTE Info,
2478 DWORD cbBuf, LPDWORD pcbNeeded)
2480 DWORD needed;
2481 const printenv_t * env_t;
2483 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2484 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2486 if(server != NULL && server[0]) {
2487 FIXME("server not supported: %s\n", debugstr_w(server));
2488 SetLastError(ERROR_INVALID_PARAMETER);
2489 return FALSE;
2492 env_t = validate_envW(env);
2493 if(!env_t) return FALSE; /* environment invalid or unsupported */
2495 if(level != 1) {
2496 WARN("(Level: %d) is ignored in win9x\n", level);
2497 SetLastError(ERROR_INVALID_LEVEL);
2498 return FALSE;
2501 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2502 needed = GetSystemDirectoryW(NULL, 0);
2503 /* add the Size for the Subdirectories */
2504 needed += lstrlenW(spoolprtprocsW);
2505 needed += lstrlenW(env_t->subdir);
2506 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2508 if(pcbNeeded) *pcbNeeded = needed;
2509 TRACE ("required: 0x%x/%d\n", needed, needed);
2510 if (needed > cbBuf) {
2511 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2512 return FALSE;
2514 if(pcbNeeded == NULL) {
2515 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2516 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2517 SetLastError(RPC_X_NULL_REF_POINTER);
2518 return FALSE;
2520 if(Info == NULL) {
2521 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2522 SetLastError(RPC_X_NULL_REF_POINTER);
2523 return FALSE;
2526 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2527 /* add the Subdirectories */
2528 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2529 lstrcatW((LPWSTR) Info, env_t->subdir);
2530 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2531 return TRUE;
2534 /*****************************************************************************
2535 * WINSPOOL_OpenDriverReg [internal]
2537 * opens the registry for the printer drivers depending on the given input
2538 * variable pEnvironment
2540 * RETURNS:
2541 * the opened hkey on success
2542 * NULL on error
2544 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
2546 HKEY retval = NULL;
2547 LPWSTR buffer;
2548 const printenv_t * env;
2550 TRACE("(%s, %d)\n",
2551 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2553 if (!pEnvironment || unicode) {
2554 /* pEnvironment was NULL or an Unicode-String: use it direct */
2555 env = validate_envW(pEnvironment);
2557 else
2559 /* pEnvironment was an ANSI-String: convert to unicode first */
2560 LPWSTR buffer;
2561 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2562 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2563 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2564 env = validate_envW(buffer);
2565 HeapFree(GetProcessHeap(), 0, buffer);
2567 if (!env) return NULL;
2569 buffer = HeapAlloc( GetProcessHeap(), 0,
2570 (strlenW(DriversW) + strlenW(env->envname) +
2571 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2572 if(buffer) {
2573 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2574 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2575 HeapFree(GetProcessHeap(), 0, buffer);
2577 return retval;
2580 /*****************************************************************************
2581 * AddPrinterW [WINSPOOL.@]
2583 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2585 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2586 LPDEVMODEA dmA;
2587 LPDEVMODEW dmW;
2588 HANDLE retval;
2589 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2590 LONG size;
2592 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2594 if(pName != NULL) {
2595 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2596 SetLastError(ERROR_INVALID_PARAMETER);
2597 return 0;
2599 if(Level != 2) {
2600 ERR("Level = %d, unsupported!\n", Level);
2601 SetLastError(ERROR_INVALID_LEVEL);
2602 return 0;
2604 if(!pPrinter) {
2605 SetLastError(ERROR_INVALID_PARAMETER);
2606 return 0;
2608 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2609 ERROR_SUCCESS) {
2610 ERR("Can't create Printers key\n");
2611 return 0;
2613 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2614 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
2615 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2616 RegCloseKey(hkeyPrinter);
2617 RegCloseKey(hkeyPrinters);
2618 return 0;
2620 RegCloseKey(hkeyPrinter);
2622 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2623 if(!hkeyDrivers) {
2624 ERR("Can't create Drivers key\n");
2625 RegCloseKey(hkeyPrinters);
2626 return 0;
2628 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2629 ERROR_SUCCESS) {
2630 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2631 RegCloseKey(hkeyPrinters);
2632 RegCloseKey(hkeyDrivers);
2633 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2634 return 0;
2636 RegCloseKey(hkeyDriver);
2637 RegCloseKey(hkeyDrivers);
2639 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2640 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2641 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2642 RegCloseKey(hkeyPrinters);
2643 return 0;
2646 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2647 ERROR_SUCCESS) {
2648 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2649 SetLastError(ERROR_INVALID_PRINTER_NAME);
2650 RegCloseKey(hkeyPrinters);
2651 return 0;
2653 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
2654 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2655 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2657 /* See if we can load the driver. We may need the devmode structure anyway
2659 * FIXME:
2660 * Note that DocumentPropertiesW will briefly try to open the printer we
2661 * just create to find a DEVMODEA struct (it will use the WINEPS default
2662 * one in case it is not there, so we are ok).
2664 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2666 if(size < 0) {
2667 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
2668 size = sizeof(DEVMODEW);
2670 if(pi->pDevMode)
2671 dmW = pi->pDevMode;
2672 else
2674 dmW = HeapAlloc(GetProcessHeap(), 0, size);
2675 ZeroMemory(dmW,size);
2676 dmW->dmSize = size;
2677 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2679 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
2680 HeapFree(GetProcessHeap(),0,dmW);
2681 dmW=NULL;
2683 else
2685 /* set devmode to printer name */
2686 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2690 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2691 and we support these drivers. NT writes DEVMODEW so somehow
2692 we'll need to distinguish between these when we support NT
2693 drivers */
2694 if (dmW)
2696 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2697 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
2698 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2699 HeapFree(GetProcessHeap(), 0, dmA);
2700 if(!pi->pDevMode)
2701 HeapFree(GetProcessHeap(), 0, dmW);
2703 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2704 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2705 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2706 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2708 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2709 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2710 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2711 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
2712 (LPBYTE)&pi->Priority, sizeof(DWORD));
2713 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2714 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2715 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
2716 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2717 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
2718 (LPBYTE)&pi->Status, sizeof(DWORD));
2719 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
2720 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2722 RegCloseKey(hkeyPrinter);
2723 RegCloseKey(hkeyPrinters);
2724 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2725 ERR("OpenPrinter failing\n");
2726 return 0;
2728 return retval;
2731 /*****************************************************************************
2732 * AddPrinterA [WINSPOOL.@]
2734 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2736 UNICODE_STRING pNameW;
2737 PWSTR pwstrNameW;
2738 PRINTER_INFO_2W *piW;
2739 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2740 HANDLE ret;
2742 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2743 if(Level != 2) {
2744 ERR("Level = %d, unsupported!\n", Level);
2745 SetLastError(ERROR_INVALID_LEVEL);
2746 return 0;
2748 pwstrNameW = asciitounicode(&pNameW,pName);
2749 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2751 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2753 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2754 RtlFreeUnicodeString(&pNameW);
2755 return ret;
2759 /*****************************************************************************
2760 * ClosePrinter [WINSPOOL.@]
2762 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2764 UINT_PTR i = (UINT_PTR)hPrinter;
2765 opened_printer_t *printer = NULL;
2766 BOOL ret = FALSE;
2768 TRACE("Handle %p\n", hPrinter);
2770 EnterCriticalSection(&printer_handles_cs);
2772 if ((i > 0) && (i <= nb_printer_handles))
2773 printer = printer_handles[i - 1];
2775 if(printer)
2777 struct list *cursor, *cursor2;
2779 if(printer->doc)
2780 EndDocPrinter(hPrinter);
2782 if(InterlockedDecrement(&printer->queue->ref) == 0)
2784 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2786 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2787 ScheduleJob(hPrinter, job->job_id);
2789 HeapFree(GetProcessHeap(), 0, printer->queue);
2791 HeapFree(GetProcessHeap(), 0, printer->name);
2792 HeapFree(GetProcessHeap(), 0, printer);
2793 printer_handles[i - 1] = NULL;
2794 ret = TRUE;
2796 LeaveCriticalSection(&printer_handles_cs);
2797 return ret;
2800 /*****************************************************************************
2801 * DeleteFormA [WINSPOOL.@]
2803 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2805 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2806 return 1;
2809 /*****************************************************************************
2810 * DeleteFormW [WINSPOOL.@]
2812 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2814 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2815 return 1;
2818 /*****************************************************************************
2819 * WINSPOOL_SHRegDeleteKey
2821 * Recursively delete subkeys.
2822 * Cut & paste from shlwapi.
2825 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
2827 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
2828 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2829 HKEY hSubKey = 0;
2831 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2832 if(!dwRet)
2834 /* Find how many subkeys there are */
2835 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
2836 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
2837 if(!dwRet)
2839 dwMaxSubkeyLen++;
2840 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
2841 /* Name too big: alloc a buffer for it */
2842 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
2844 if(!lpszName)
2845 dwRet = ERROR_NOT_ENOUGH_MEMORY;
2846 else
2848 /* Recursively delete all the subkeys */
2849 for(i = 0; i < dwKeyCount && !dwRet; i++)
2851 dwSize = dwMaxSubkeyLen;
2852 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
2853 if(!dwRet)
2854 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
2857 if (lpszName != szNameBuf)
2858 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
2862 RegCloseKey(hSubKey);
2863 if(!dwRet)
2864 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
2866 return dwRet;
2869 /*****************************************************************************
2870 * DeletePrinter [WINSPOOL.@]
2872 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2874 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2875 HKEY hkeyPrinters, hkey;
2877 if(!lpNameW) {
2878 SetLastError(ERROR_INVALID_HANDLE);
2879 return FALSE;
2881 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2882 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
2883 RegCloseKey(hkeyPrinters);
2885 WriteProfileStringW(devicesW, lpNameW, NULL);
2886 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2887 RegDeleteValueW(hkey, lpNameW);
2888 RegCloseKey(hkey);
2890 return TRUE;
2893 /*****************************************************************************
2894 * SetPrinterA [WINSPOOL.@]
2896 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2897 DWORD Command)
2899 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2900 return FALSE;
2903 /*****************************************************************************
2904 * SetJobA [WINSPOOL.@]
2906 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2907 LPBYTE pJob, DWORD Command)
2909 BOOL ret;
2910 LPBYTE JobW;
2911 UNICODE_STRING usBuffer;
2913 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2915 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2916 are all ignored by SetJob, so we don't bother copying them */
2917 switch(Level)
2919 case 0:
2920 JobW = NULL;
2921 break;
2922 case 1:
2924 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2925 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2927 JobW = (LPBYTE)info1W;
2928 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2929 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2930 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2931 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2932 info1W->Status = info1A->Status;
2933 info1W->Priority = info1A->Priority;
2934 info1W->Position = info1A->Position;
2935 info1W->PagesPrinted = info1A->PagesPrinted;
2936 break;
2938 case 2:
2940 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2941 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2943 JobW = (LPBYTE)info2W;
2944 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2945 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2946 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2947 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2948 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2949 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2950 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2951 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2952 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2953 info2W->Status = info2A->Status;
2954 info2W->Priority = info2A->Priority;
2955 info2W->Position = info2A->Position;
2956 info2W->StartTime = info2A->StartTime;
2957 info2W->UntilTime = info2A->UntilTime;
2958 info2W->PagesPrinted = info2A->PagesPrinted;
2959 break;
2961 case 3:
2962 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2963 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2964 break;
2965 default:
2966 SetLastError(ERROR_INVALID_LEVEL);
2967 return FALSE;
2970 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2972 switch(Level)
2974 case 1:
2976 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2977 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2978 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2979 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2980 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2981 break;
2983 case 2:
2985 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2986 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2987 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2988 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2989 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2990 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2991 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2992 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2993 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2994 break;
2997 HeapFree(GetProcessHeap(), 0, JobW);
2999 return ret;
3002 /*****************************************************************************
3003 * SetJobW [WINSPOOL.@]
3005 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3006 LPBYTE pJob, DWORD Command)
3008 BOOL ret = FALSE;
3009 job_t *job;
3011 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3012 FIXME("Ignoring everything other than document title\n");
3014 EnterCriticalSection(&printer_handles_cs);
3015 job = get_job(hPrinter, JobId);
3016 if(!job)
3017 goto end;
3019 switch(Level)
3021 case 0:
3022 break;
3023 case 1:
3025 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3026 HeapFree(GetProcessHeap(), 0, job->document_title);
3027 job->document_title = strdupW(info1->pDocument);
3028 break;
3030 case 2:
3032 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3033 HeapFree(GetProcessHeap(), 0, job->document_title);
3034 job->document_title = strdupW(info2->pDocument);
3035 break;
3037 case 3:
3038 break;
3039 default:
3040 SetLastError(ERROR_INVALID_LEVEL);
3041 goto end;
3043 ret = TRUE;
3044 end:
3045 LeaveCriticalSection(&printer_handles_cs);
3046 return ret;
3049 /*****************************************************************************
3050 * EndDocPrinter [WINSPOOL.@]
3052 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3054 opened_printer_t *printer;
3055 BOOL ret = FALSE;
3056 TRACE("(%p)\n", hPrinter);
3058 EnterCriticalSection(&printer_handles_cs);
3060 printer = get_opened_printer(hPrinter);
3061 if(!printer)
3063 SetLastError(ERROR_INVALID_HANDLE);
3064 goto end;
3067 if(!printer->doc)
3069 SetLastError(ERROR_SPL_NO_STARTDOC);
3070 goto end;
3073 CloseHandle(printer->doc->hf);
3074 ScheduleJob(hPrinter, printer->doc->job_id);
3075 HeapFree(GetProcessHeap(), 0, printer->doc);
3076 printer->doc = NULL;
3077 ret = TRUE;
3078 end:
3079 LeaveCriticalSection(&printer_handles_cs);
3080 return ret;
3083 /*****************************************************************************
3084 * EndPagePrinter [WINSPOOL.@]
3086 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3088 FIXME("(%p): stub\n", hPrinter);
3089 return TRUE;
3092 /*****************************************************************************
3093 * StartDocPrinterA [WINSPOOL.@]
3095 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3097 UNICODE_STRING usBuffer;
3098 DOC_INFO_2W doc2W;
3099 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3100 DWORD ret;
3102 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3103 or one (DOC_INFO_3) extra DWORDs */
3105 switch(Level) {
3106 case 2:
3107 doc2W.JobId = doc2->JobId;
3108 /* fall through */
3109 case 3:
3110 doc2W.dwMode = doc2->dwMode;
3111 /* fall through */
3112 case 1:
3113 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3114 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3115 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3116 break;
3118 default:
3119 SetLastError(ERROR_INVALID_LEVEL);
3120 return FALSE;
3123 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3125 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3126 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3127 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3129 return ret;
3132 /*****************************************************************************
3133 * StartDocPrinterW [WINSPOOL.@]
3135 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3137 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3138 opened_printer_t *printer;
3139 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3140 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3141 JOB_INFO_1W job_info;
3142 DWORD needed, ret = 0;
3143 HANDLE hf;
3144 WCHAR *filename;
3146 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3147 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3148 debugstr_w(doc->pDatatype));
3150 if(Level < 1 || Level > 3)
3152 SetLastError(ERROR_INVALID_LEVEL);
3153 return 0;
3156 EnterCriticalSection(&printer_handles_cs);
3157 printer = get_opened_printer(hPrinter);
3158 if(!printer)
3160 SetLastError(ERROR_INVALID_HANDLE);
3161 goto end;
3164 if(printer->doc)
3166 SetLastError(ERROR_INVALID_PRINTER_STATE);
3167 goto end;
3170 /* Even if we're printing to a file we still add a print job, we'll
3171 just ignore the spool file name */
3173 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3175 ERR("AddJob failed gle %08x\n", GetLastError());
3176 goto end;
3179 if(doc->pOutputFile)
3180 filename = doc->pOutputFile;
3181 else
3182 filename = addjob->Path;
3184 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3185 if(hf == INVALID_HANDLE_VALUE)
3186 goto end;
3188 memset(&job_info, 0, sizeof(job_info));
3189 job_info.pDocument = doc->pDocName;
3190 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3192 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3193 printer->doc->hf = hf;
3194 ret = printer->doc->job_id = addjob->JobId;
3195 end:
3196 LeaveCriticalSection(&printer_handles_cs);
3198 return ret;
3201 /*****************************************************************************
3202 * StartPagePrinter [WINSPOOL.@]
3204 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3206 FIXME("(%p): stub\n", hPrinter);
3207 return TRUE;
3210 /*****************************************************************************
3211 * GetFormA [WINSPOOL.@]
3213 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3214 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3216 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3217 Level,pForm,cbBuf,pcbNeeded);
3218 return FALSE;
3221 /*****************************************************************************
3222 * GetFormW [WINSPOOL.@]
3224 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3225 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3227 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3228 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3229 return FALSE;
3232 /*****************************************************************************
3233 * SetFormA [WINSPOOL.@]
3235 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3236 LPBYTE pForm)
3238 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3239 return FALSE;
3242 /*****************************************************************************
3243 * SetFormW [WINSPOOL.@]
3245 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3246 LPBYTE pForm)
3248 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3249 return FALSE;
3252 /*****************************************************************************
3253 * ReadPrinter [WINSPOOL.@]
3255 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3256 LPDWORD pNoBytesRead)
3258 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3259 return FALSE;
3262 /*****************************************************************************
3263 * ResetPrinterA [WINSPOOL.@]
3265 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3267 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3268 return FALSE;
3271 /*****************************************************************************
3272 * ResetPrinterW [WINSPOOL.@]
3274 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3276 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3277 return FALSE;
3280 /*****************************************************************************
3281 * WINSPOOL_GetDWORDFromReg
3283 * Return DWORD associated with ValueName from hkey.
3285 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3287 DWORD sz = sizeof(DWORD), type, value = 0;
3288 LONG ret;
3290 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3292 if(ret != ERROR_SUCCESS) {
3293 WARN("Got ret = %d on name %s\n", ret, ValueName);
3294 return 0;
3296 if(type != REG_DWORD) {
3297 ERR("Got type %d\n", type);
3298 return 0;
3300 return value;
3303 /*****************************************************************************
3304 * WINSPOOL_GetStringFromReg
3306 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3307 * String is stored either as unicode or ascii.
3308 * Bit of a hack here to get the ValueName if we want ascii.
3310 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3311 DWORD buflen, DWORD *needed,
3312 BOOL unicode)
3314 DWORD sz = buflen, type;
3315 LONG ret;
3317 if(unicode)
3318 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3319 else {
3320 LPSTR ValueNameA = strdupWtoA(ValueName);
3321 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3322 HeapFree(GetProcessHeap(),0,ValueNameA);
3324 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3325 WARN("Got ret = %d\n", ret);
3326 *needed = 0;
3327 return FALSE;
3329 /* add space for terminating '\0' */
3330 sz += unicode ? sizeof(WCHAR) : 1;
3331 *needed = sz;
3333 if (ptr)
3334 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3336 return TRUE;
3339 /*****************************************************************************
3340 * WINSPOOL_GetDefaultDevMode
3342 * Get a default DevMode values for wineps.
3343 * FIXME - use ppd.
3346 static void WINSPOOL_GetDefaultDevMode(
3347 LPBYTE ptr,
3348 DWORD buflen, DWORD *needed,
3349 BOOL unicode)
3351 DEVMODEA dm;
3352 static const char szwps[] = "wineps.drv";
3354 /* fill default DEVMODE - should be read from ppd... */
3355 ZeroMemory( &dm, sizeof(dm) );
3356 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3357 dm.dmSpecVersion = DM_SPECVERSION;
3358 dm.dmDriverVersion = 1;
3359 dm.dmSize = sizeof(DEVMODEA);
3360 dm.dmDriverExtra = 0;
3361 dm.dmFields =
3362 DM_ORIENTATION | DM_PAPERSIZE |
3363 DM_PAPERLENGTH | DM_PAPERWIDTH |
3364 DM_SCALE |
3365 DM_COPIES |
3366 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3367 DM_YRESOLUTION | DM_TTOPTION;
3369 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3370 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3371 dm.u1.s1.dmPaperLength = 2970;
3372 dm.u1.s1.dmPaperWidth = 2100;
3374 dm.dmScale = 100;
3375 dm.dmCopies = 1;
3376 dm.dmDefaultSource = DMBIN_AUTO;
3377 dm.dmPrintQuality = DMRES_MEDIUM;
3378 /* dm.dmColor */
3379 /* dm.dmDuplex */
3380 dm.dmYResolution = 300; /* 300dpi */
3381 dm.dmTTOption = DMTT_BITMAP;
3382 /* dm.dmCollate */
3383 /* dm.dmFormName */
3384 /* dm.dmLogPixels */
3385 /* dm.dmBitsPerPel */
3386 /* dm.dmPelsWidth */
3387 /* dm.dmPelsHeight */
3388 /* dm.dmDisplayFlags */
3389 /* dm.dmDisplayFrequency */
3390 /* dm.dmICMMethod */
3391 /* dm.dmICMIntent */
3392 /* dm.dmMediaType */
3393 /* dm.dmDitherType */
3394 /* dm.dmReserved1 */
3395 /* dm.dmReserved2 */
3396 /* dm.dmPanningWidth */
3397 /* dm.dmPanningHeight */
3399 if(unicode) {
3400 if(buflen >= sizeof(DEVMODEW)) {
3401 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3402 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3403 HeapFree(GetProcessHeap(),0,pdmW);
3405 *needed = sizeof(DEVMODEW);
3407 else
3409 if(buflen >= sizeof(DEVMODEA)) {
3410 memcpy(ptr, &dm, sizeof(DEVMODEA));
3412 *needed = sizeof(DEVMODEA);
3416 /*****************************************************************************
3417 * WINSPOOL_GetDevModeFromReg
3419 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3420 * DevMode is stored either as unicode or ascii.
3422 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3423 LPBYTE ptr,
3424 DWORD buflen, DWORD *needed,
3425 BOOL unicode)
3427 DWORD sz = buflen, type;
3428 LONG ret;
3430 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3431 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3432 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3433 if (sz < sizeof(DEVMODEA))
3435 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3436 return FALSE;
3438 /* ensures that dmSize is not erratically bogus if registry is invalid */
3439 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3440 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3441 if(unicode) {
3442 sz += (CCHDEVICENAME + CCHFORMNAME);
3443 if(buflen >= sz) {
3444 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3445 memcpy(ptr, dmW, sz);
3446 HeapFree(GetProcessHeap(),0,dmW);
3449 *needed = sz;
3450 return TRUE;
3453 /*********************************************************************
3454 * WINSPOOL_GetPrinter_2
3456 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3457 * The strings are either stored as unicode or ascii.
3459 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3460 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3461 BOOL unicode)
3463 DWORD size, left = cbBuf;
3464 BOOL space = (cbBuf > 0);
3465 LPBYTE ptr = buf;
3467 *pcbNeeded = 0;
3469 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3470 unicode)) {
3471 if(space && size <= left) {
3472 pi2->pPrinterName = (LPWSTR)ptr;
3473 ptr += size;
3474 left -= size;
3475 } else
3476 space = FALSE;
3477 *pcbNeeded += size;
3479 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3480 unicode)) {
3481 if(space && size <= left) {
3482 pi2->pShareName = (LPWSTR)ptr;
3483 ptr += size;
3484 left -= size;
3485 } else
3486 space = FALSE;
3487 *pcbNeeded += size;
3489 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3490 unicode)) {
3491 if(space && size <= left) {
3492 pi2->pPortName = (LPWSTR)ptr;
3493 ptr += size;
3494 left -= size;
3495 } else
3496 space = FALSE;
3497 *pcbNeeded += size;
3499 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3500 &size, unicode)) {
3501 if(space && size <= left) {
3502 pi2->pDriverName = (LPWSTR)ptr;
3503 ptr += size;
3504 left -= size;
3505 } else
3506 space = FALSE;
3507 *pcbNeeded += size;
3509 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3510 unicode)) {
3511 if(space && size <= left) {
3512 pi2->pComment = (LPWSTR)ptr;
3513 ptr += size;
3514 left -= size;
3515 } else
3516 space = FALSE;
3517 *pcbNeeded += size;
3519 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3520 unicode)) {
3521 if(space && size <= left) {
3522 pi2->pLocation = (LPWSTR)ptr;
3523 ptr += size;
3524 left -= size;
3525 } else
3526 space = FALSE;
3527 *pcbNeeded += size;
3529 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3530 &size, unicode)) {
3531 if(space && size <= left) {
3532 pi2->pDevMode = (LPDEVMODEW)ptr;
3533 ptr += size;
3534 left -= size;
3535 } else
3536 space = FALSE;
3537 *pcbNeeded += size;
3539 else
3541 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3542 if(space && size <= left) {
3543 pi2->pDevMode = (LPDEVMODEW)ptr;
3544 ptr += size;
3545 left -= size;
3546 } else
3547 space = FALSE;
3548 *pcbNeeded += size;
3550 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3551 &size, unicode)) {
3552 if(space && size <= left) {
3553 pi2->pSepFile = (LPWSTR)ptr;
3554 ptr += size;
3555 left -= size;
3556 } else
3557 space = FALSE;
3558 *pcbNeeded += size;
3560 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3561 &size, unicode)) {
3562 if(space && size <= left) {
3563 pi2->pPrintProcessor = (LPWSTR)ptr;
3564 ptr += size;
3565 left -= size;
3566 } else
3567 space = FALSE;
3568 *pcbNeeded += size;
3570 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3571 &size, unicode)) {
3572 if(space && size <= left) {
3573 pi2->pDatatype = (LPWSTR)ptr;
3574 ptr += size;
3575 left -= size;
3576 } else
3577 space = FALSE;
3578 *pcbNeeded += size;
3580 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3581 &size, unicode)) {
3582 if(space && size <= left) {
3583 pi2->pParameters = (LPWSTR)ptr;
3584 ptr += size;
3585 left -= size;
3586 } else
3587 space = FALSE;
3588 *pcbNeeded += size;
3590 if(pi2) {
3591 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3592 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3593 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3594 "Default Priority");
3595 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3596 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3599 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3600 memset(pi2, 0, sizeof(*pi2));
3602 return space;
3605 /*********************************************************************
3606 * WINSPOOL_GetPrinter_4
3608 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3610 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3611 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3612 BOOL unicode)
3614 DWORD size, left = cbBuf;
3615 BOOL space = (cbBuf > 0);
3616 LPBYTE ptr = buf;
3618 *pcbNeeded = 0;
3620 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3621 unicode)) {
3622 if(space && size <= left) {
3623 pi4->pPrinterName = (LPWSTR)ptr;
3624 ptr += size;
3625 left -= size;
3626 } else
3627 space = FALSE;
3628 *pcbNeeded += size;
3630 if(pi4) {
3631 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3634 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3635 memset(pi4, 0, sizeof(*pi4));
3637 return space;
3640 /*********************************************************************
3641 * WINSPOOL_GetPrinter_5
3643 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3645 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3646 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3647 BOOL unicode)
3649 DWORD size, left = cbBuf;
3650 BOOL space = (cbBuf > 0);
3651 LPBYTE ptr = buf;
3653 *pcbNeeded = 0;
3655 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3656 unicode)) {
3657 if(space && size <= left) {
3658 pi5->pPrinterName = (LPWSTR)ptr;
3659 ptr += size;
3660 left -= size;
3661 } else
3662 space = FALSE;
3663 *pcbNeeded += size;
3665 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3666 unicode)) {
3667 if(space && size <= left) {
3668 pi5->pPortName = (LPWSTR)ptr;
3669 ptr += size;
3670 left -= size;
3671 } else
3672 space = FALSE;
3673 *pcbNeeded += size;
3675 if(pi5) {
3676 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3677 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3678 "dnsTimeout");
3679 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3680 "txTimeout");
3683 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3684 memset(pi5, 0, sizeof(*pi5));
3686 return space;
3689 /*****************************************************************************
3690 * WINSPOOL_GetPrinter
3692 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3693 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3694 * just a collection of pointers to strings.
3696 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3697 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3699 LPCWSTR name;
3700 DWORD size, needed = 0;
3701 LPBYTE ptr = NULL;
3702 HKEY hkeyPrinter, hkeyPrinters;
3703 BOOL ret;
3705 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3707 if (!(name = get_opened_printer_name(hPrinter))) {
3708 SetLastError(ERROR_INVALID_HANDLE);
3709 return FALSE;
3712 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3713 ERROR_SUCCESS) {
3714 ERR("Can't create Printers key\n");
3715 return FALSE;
3717 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3719 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3720 RegCloseKey(hkeyPrinters);
3721 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3722 return FALSE;
3725 switch(Level) {
3726 case 2:
3728 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3730 size = sizeof(PRINTER_INFO_2W);
3731 if(size <= cbBuf) {
3732 ptr = pPrinter + size;
3733 cbBuf -= size;
3734 memset(pPrinter, 0, size);
3735 } else {
3736 pi2 = NULL;
3737 cbBuf = 0;
3739 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3740 unicode);
3741 needed += size;
3742 break;
3745 case 4:
3747 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3749 size = sizeof(PRINTER_INFO_4W);
3750 if(size <= cbBuf) {
3751 ptr = pPrinter + size;
3752 cbBuf -= size;
3753 memset(pPrinter, 0, size);
3754 } else {
3755 pi4 = NULL;
3756 cbBuf = 0;
3758 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
3759 unicode);
3760 needed += size;
3761 break;
3765 case 5:
3767 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3769 size = sizeof(PRINTER_INFO_5W);
3770 if(size <= cbBuf) {
3771 ptr = pPrinter + size;
3772 cbBuf -= size;
3773 memset(pPrinter, 0, size);
3774 } else {
3775 pi5 = NULL;
3776 cbBuf = 0;
3779 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
3780 unicode);
3781 needed += size;
3782 break;
3785 default:
3786 FIXME("Unimplemented level %d\n", Level);
3787 SetLastError(ERROR_INVALID_LEVEL);
3788 RegCloseKey(hkeyPrinters);
3789 RegCloseKey(hkeyPrinter);
3790 return FALSE;
3793 RegCloseKey(hkeyPrinter);
3794 RegCloseKey(hkeyPrinters);
3796 TRACE("returning %d needed = %d\n", ret, needed);
3797 if(pcbNeeded) *pcbNeeded = needed;
3798 if(!ret)
3799 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3800 return ret;
3803 /*****************************************************************************
3804 * GetPrinterW [WINSPOOL.@]
3806 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3807 DWORD cbBuf, LPDWORD pcbNeeded)
3809 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3810 TRUE);
3813 /*****************************************************************************
3814 * GetPrinterA [WINSPOOL.@]
3816 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3817 DWORD cbBuf, LPDWORD pcbNeeded)
3819 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3820 FALSE);
3823 /*****************************************************************************
3824 * WINSPOOL_EnumPrinters
3826 * Implementation of EnumPrintersA|W
3828 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
3829 DWORD dwLevel, LPBYTE lpbPrinters,
3830 DWORD cbBuf, LPDWORD lpdwNeeded,
3831 LPDWORD lpdwReturned, BOOL unicode)
3834 HKEY hkeyPrinters, hkeyPrinter;
3835 WCHAR PrinterName[255];
3836 DWORD needed = 0, number = 0;
3837 DWORD used, i, left;
3838 PBYTE pi, buf;
3840 if(lpbPrinters)
3841 memset(lpbPrinters, 0, cbBuf);
3842 if(lpdwReturned)
3843 *lpdwReturned = 0;
3844 if(lpdwNeeded)
3845 *lpdwNeeded = 0;
3847 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3848 if(dwType == PRINTER_ENUM_DEFAULT)
3849 return TRUE;
3851 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3852 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3853 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3854 if(!dwType) return TRUE;
3857 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3858 FIXME("dwType = %08x\n", dwType);
3859 SetLastError(ERROR_INVALID_FLAGS);
3860 return FALSE;
3863 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3864 ERROR_SUCCESS) {
3865 ERR("Can't create Printers key\n");
3866 return FALSE;
3869 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3870 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3871 RegCloseKey(hkeyPrinters);
3872 ERR("Can't query Printers key\n");
3873 return FALSE;
3875 TRACE("Found %d printers\n", number);
3877 switch(dwLevel) {
3878 case 1:
3879 RegCloseKey(hkeyPrinters);
3880 if (lpdwReturned)
3881 *lpdwReturned = number;
3882 return TRUE;
3884 case 2:
3885 used = number * sizeof(PRINTER_INFO_2W);
3886 break;
3887 case 4:
3888 used = number * sizeof(PRINTER_INFO_4W);
3889 break;
3890 case 5:
3891 used = number * sizeof(PRINTER_INFO_5W);
3892 break;
3894 default:
3895 SetLastError(ERROR_INVALID_LEVEL);
3896 RegCloseKey(hkeyPrinters);
3897 return FALSE;
3899 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3901 for(i = 0; i < number; i++) {
3902 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
3903 ERROR_SUCCESS) {
3904 ERR("Can't enum key number %d\n", i);
3905 RegCloseKey(hkeyPrinters);
3906 return FALSE;
3908 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
3909 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3910 ERROR_SUCCESS) {
3911 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3912 RegCloseKey(hkeyPrinters);
3913 return FALSE;
3916 if(cbBuf > used) {
3917 buf = lpbPrinters + used;
3918 left = cbBuf - used;
3919 } else {
3920 buf = NULL;
3921 left = 0;
3924 switch(dwLevel) {
3925 case 2:
3926 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
3927 left, &needed, unicode);
3928 used += needed;
3929 if(pi) pi += sizeof(PRINTER_INFO_2W);
3930 break;
3931 case 4:
3932 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
3933 left, &needed, unicode);
3934 used += needed;
3935 if(pi) pi += sizeof(PRINTER_INFO_4W);
3936 break;
3937 case 5:
3938 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
3939 left, &needed, unicode);
3940 used += needed;
3941 if(pi) pi += sizeof(PRINTER_INFO_5W);
3942 break;
3943 default:
3944 ERR("Shouldn't be here!\n");
3945 RegCloseKey(hkeyPrinter);
3946 RegCloseKey(hkeyPrinters);
3947 return FALSE;
3949 RegCloseKey(hkeyPrinter);
3951 RegCloseKey(hkeyPrinters);
3953 if(lpdwNeeded)
3954 *lpdwNeeded = used;
3956 if(used > cbBuf) {
3957 if(lpbPrinters)
3958 memset(lpbPrinters, 0, cbBuf);
3959 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3960 return FALSE;
3962 if(lpdwReturned)
3963 *lpdwReturned = number;
3964 SetLastError(ERROR_SUCCESS);
3965 return TRUE;
3969 /******************************************************************
3970 * EnumPrintersW [WINSPOOL.@]
3972 * Enumerates the available printers, print servers and print
3973 * providers, depending on the specified flags, name and level.
3975 * RETURNS:
3977 * If level is set to 1:
3978 * Not implemented yet!
3979 * Returns TRUE with an empty list.
3981 * If level is set to 2:
3982 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3983 * Returns an array of PRINTER_INFO_2 data structures in the
3984 * lpbPrinters buffer. Note that according to MSDN also an
3985 * OpenPrinter should be performed on every remote printer.
3987 * If level is set to 4 (officially WinNT only):
3988 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3989 * Fast: Only the registry is queried to retrieve printer names,
3990 * no connection to the driver is made.
3991 * Returns an array of PRINTER_INFO_4 data structures in the
3992 * lpbPrinters buffer.
3994 * If level is set to 5 (officially WinNT4/Win9x only):
3995 * Fast: Only the registry is queried to retrieve printer names,
3996 * no connection to the driver is made.
3997 * Returns an array of PRINTER_INFO_5 data structures in the
3998 * lpbPrinters buffer.
4000 * If level set to 3 or 6+:
4001 * returns zero (failure!)
4003 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4004 * for information.
4006 * BUGS:
4007 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4008 * - Only levels 2, 4 and 5 are implemented at the moment.
4009 * - 16-bit printer drivers are not enumerated.
4010 * - Returned amount of bytes used/needed does not match the real Windoze
4011 * implementation (as in this implementation, all strings are part
4012 * of the buffer, whereas Win32 keeps them somewhere else)
4013 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4015 * NOTE:
4016 * - In a regular Wine installation, no registry settings for printers
4017 * exist, which makes this function return an empty list.
4019 BOOL WINAPI EnumPrintersW(
4020 DWORD dwType, /* [in] Types of print objects to enumerate */
4021 LPWSTR lpszName, /* [in] name of objects to enumerate */
4022 DWORD dwLevel, /* [in] type of printer info structure */
4023 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4024 DWORD cbBuf, /* [in] max size of buffer in bytes */
4025 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4026 LPDWORD lpdwReturned /* [out] number of entries returned */
4029 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4030 lpdwNeeded, lpdwReturned, TRUE);
4033 /******************************************************************
4034 * EnumPrintersA [WINSPOOL.@]
4037 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
4038 DWORD dwLevel, LPBYTE lpbPrinters,
4039 DWORD cbBuf, LPDWORD lpdwNeeded,
4040 LPDWORD lpdwReturned)
4042 BOOL ret, unicode = FALSE;
4043 UNICODE_STRING lpszNameW;
4044 PWSTR pwstrNameW;
4046 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
4047 if(!cbBuf) unicode = TRUE; /* return a buffer that's big enough for the unicode version */
4048 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
4049 lpdwNeeded, lpdwReturned, unicode);
4050 RtlFreeUnicodeString(&lpszNameW);
4051 return ret;
4054 /*****************************************************************************
4055 * WINSPOOL_GetDriverInfoFromReg [internal]
4057 * Enters the information from the registry into the DRIVER_INFO struct
4059 * RETURNS
4060 * zero if the printer driver does not exist in the registry
4061 * (only if Level > 1) otherwise nonzero
4063 static BOOL WINSPOOL_GetDriverInfoFromReg(
4064 HKEY hkeyDrivers,
4065 LPWSTR DriverName,
4066 LPCWSTR pEnvironment,
4067 DWORD Level,
4068 LPBYTE ptr, /* DRIVER_INFO */
4069 LPBYTE pDriverStrings, /* strings buffer */
4070 DWORD cbBuf, /* size of string buffer */
4071 LPDWORD pcbNeeded, /* space needed for str. */
4072 BOOL unicode) /* type of strings */
4074 DWORD size, tmp;
4075 HKEY hkeyDriver;
4076 LPBYTE strPtr = pDriverStrings;
4078 TRACE("%s,%s,%d,%p,%p,%d,%d\n",
4079 debugstr_w(DriverName), debugstr_w(pEnvironment),
4080 Level, ptr, pDriverStrings, cbBuf, unicode);
4082 if(unicode) {
4083 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4084 if (*pcbNeeded <= cbBuf)
4085 strcpyW((LPWSTR)strPtr, DriverName);
4086 } else {
4087 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
4088 NULL, NULL);
4089 if(*pcbNeeded <= cbBuf)
4090 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
4091 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4093 if(Level == 1) {
4094 if(ptr)
4095 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
4096 return TRUE;
4097 } else {
4098 if(ptr)
4099 ((PDRIVER_INFO_2W) ptr)->pName = (LPWSTR) strPtr;
4100 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4103 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4104 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
4105 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4106 return FALSE;
4109 if(ptr)
4110 ((PDRIVER_INFO_2A) ptr)->cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
4112 if(!pEnvironment)
4113 pEnvironment = DefaultEnvironmentW;
4114 if(unicode)
4115 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
4116 else
4117 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
4118 NULL, NULL);
4119 *pcbNeeded += size;
4120 if(*pcbNeeded <= cbBuf) {
4121 if(unicode)
4122 strcpyW((LPWSTR)strPtr, pEnvironment);
4123 else
4124 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
4125 (LPSTR)strPtr, size, NULL, NULL);
4126 if(ptr)
4127 ((PDRIVER_INFO_2W) ptr)->pEnvironment = (LPWSTR)strPtr;
4128 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4131 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
4132 unicode)) {
4133 *pcbNeeded += size;
4134 if(*pcbNeeded <= cbBuf)
4135 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
4136 unicode);
4137 if(ptr)
4138 ((PDRIVER_INFO_2W) ptr)->pDriverPath = (LPWSTR)strPtr;
4139 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4142 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
4143 unicode)) {
4144 *pcbNeeded += size;
4145 if(*pcbNeeded <= cbBuf)
4146 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
4147 &tmp, unicode);
4148 if(ptr)
4149 ((PDRIVER_INFO_2W) ptr)->pDataFile = (LPWSTR)strPtr;
4150 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4153 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
4154 0, &size, unicode)) {
4155 *pcbNeeded += size;
4156 if(*pcbNeeded <= cbBuf)
4157 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
4158 size, &tmp, unicode);
4159 if(ptr)
4160 ((PDRIVER_INFO_2W) ptr)->pConfigFile = (LPWSTR)strPtr;
4161 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4164 if(Level == 2 ) {
4165 RegCloseKey(hkeyDriver);
4166 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4167 return TRUE;
4170 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
4171 unicode)) {
4172 *pcbNeeded += size;
4173 if(*pcbNeeded <= cbBuf)
4174 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
4175 size, &tmp, unicode);
4176 if(ptr)
4177 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
4178 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4181 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
4182 &size, unicode)) {
4183 *pcbNeeded += size;
4184 if(*pcbNeeded <= cbBuf)
4185 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
4186 size, &tmp, unicode);
4187 if(ptr)
4188 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
4189 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4192 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
4193 unicode)) {
4194 *pcbNeeded += size;
4195 if(*pcbNeeded <= cbBuf)
4196 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
4197 size, &tmp, unicode);
4198 if(ptr)
4199 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
4200 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4203 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
4204 unicode)) {
4205 *pcbNeeded += size;
4206 if(*pcbNeeded <= cbBuf)
4207 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
4208 size, &tmp, unicode);
4209 if(ptr)
4210 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
4211 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4214 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4215 RegCloseKey(hkeyDriver);
4216 return TRUE;
4219 /*****************************************************************************
4220 * WINSPOOL_GetPrinterDriver
4222 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
4223 DWORD Level, LPBYTE pDriverInfo,
4224 DWORD cbBuf, LPDWORD pcbNeeded,
4225 BOOL unicode)
4227 LPCWSTR name;
4228 WCHAR DriverName[100];
4229 DWORD ret, type, size, needed = 0;
4230 LPBYTE ptr = NULL;
4231 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4233 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4234 Level,pDriverInfo,cbBuf, pcbNeeded);
4236 ZeroMemory(pDriverInfo, cbBuf);
4238 if (!(name = get_opened_printer_name(hPrinter))) {
4239 SetLastError(ERROR_INVALID_HANDLE);
4240 return FALSE;
4242 if(Level < 1 || Level > 6) {
4243 SetLastError(ERROR_INVALID_LEVEL);
4244 return FALSE;
4246 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4247 ERROR_SUCCESS) {
4248 ERR("Can't create Printers key\n");
4249 return FALSE;
4251 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4252 != ERROR_SUCCESS) {
4253 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4254 RegCloseKey(hkeyPrinters);
4255 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4256 return FALSE;
4258 size = sizeof(DriverName);
4259 DriverName[0] = 0;
4260 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4261 (LPBYTE)DriverName, &size);
4262 RegCloseKey(hkeyPrinter);
4263 RegCloseKey(hkeyPrinters);
4264 if(ret != ERROR_SUCCESS) {
4265 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4266 return FALSE;
4269 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4270 if(!hkeyDrivers) {
4271 ERR("Can't create Drivers key\n");
4272 return FALSE;
4275 switch(Level) {
4276 case 1:
4277 size = sizeof(DRIVER_INFO_1W);
4278 break;
4279 case 2:
4280 size = sizeof(DRIVER_INFO_2W);
4281 break;
4282 case 3:
4283 size = sizeof(DRIVER_INFO_3W);
4284 break;
4285 case 4:
4286 size = sizeof(DRIVER_INFO_4W);
4287 break;
4288 case 5:
4289 size = sizeof(DRIVER_INFO_5W);
4290 break;
4291 case 6:
4292 size = sizeof(DRIVER_INFO_6W);
4293 break;
4294 default:
4295 ERR("Invalid level\n");
4296 return FALSE;
4299 if(size <= cbBuf)
4300 ptr = pDriverInfo + size;
4302 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4303 pEnvironment, Level, pDriverInfo,
4304 (cbBuf < size) ? NULL : ptr,
4305 (cbBuf < size) ? 0 : cbBuf - size,
4306 &needed, unicode)) {
4307 RegCloseKey(hkeyDrivers);
4308 return FALSE;
4311 RegCloseKey(hkeyDrivers);
4313 if(pcbNeeded) *pcbNeeded = size + needed;
4314 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4315 if(cbBuf >= needed) return TRUE;
4316 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4317 return FALSE;
4320 /*****************************************************************************
4321 * GetPrinterDriverA [WINSPOOL.@]
4323 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4324 DWORD Level, LPBYTE pDriverInfo,
4325 DWORD cbBuf, LPDWORD pcbNeeded)
4327 BOOL ret;
4328 UNICODE_STRING pEnvW;
4329 PWSTR pwstrEnvW;
4331 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4332 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4333 cbBuf, pcbNeeded, FALSE);
4334 RtlFreeUnicodeString(&pEnvW);
4335 return ret;
4337 /*****************************************************************************
4338 * GetPrinterDriverW [WINSPOOL.@]
4340 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4341 DWORD Level, LPBYTE pDriverInfo,
4342 DWORD cbBuf, LPDWORD pcbNeeded)
4344 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4345 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4348 /*****************************************************************************
4349 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4351 * Return the PATH for the Printer-Drivers (UNICODE)
4353 * PARAMS
4354 * pName [I] Servername (NT only) or NULL (local Computer)
4355 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4356 * Level [I] Structure-Level (must be 1)
4357 * pDriverDirectory [O] PTR to Buffer that receives the Result
4358 * cbBuf [I] Size of Buffer at pDriverDirectory
4359 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4360 * required for pDriverDirectory
4362 * RETURNS
4363 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4364 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4365 * if cbBuf is too small
4367 * Native Values returned in pDriverDirectory on Success:
4368 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4369 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4370 *| win9x(Windows 4.0): "%winsysdir%"
4372 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4374 * FIXME
4375 *- Only NULL or "" is supported for pName
4378 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4379 DWORD Level, LPBYTE pDriverDirectory,
4380 DWORD cbBuf, LPDWORD pcbNeeded)
4382 DWORD needed;
4383 const printenv_t * env;
4385 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4386 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4387 if(pName != NULL && pName[0]) {
4388 FIXME("pName unsupported: %s\n", debugstr_w(pName));
4389 SetLastError(ERROR_INVALID_PARAMETER);
4390 return FALSE;
4393 env = validate_envW(pEnvironment);
4394 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
4396 if(Level != 1) {
4397 WARN("(Level: %d) is ignored in win9x\n", Level);
4398 SetLastError(ERROR_INVALID_LEVEL);
4399 return FALSE;
4402 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
4403 needed = GetSystemDirectoryW(NULL, 0);
4404 /* add the Size for the Subdirectories */
4405 needed += lstrlenW(spooldriversW);
4406 needed += lstrlenW(env->subdir);
4407 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
4409 if(pcbNeeded)
4410 *pcbNeeded = needed;
4411 TRACE("required: 0x%x/%d\n", needed, needed);
4412 if(needed > cbBuf) {
4413 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4414 return FALSE;
4416 if(pcbNeeded == NULL) {
4417 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
4418 SetLastError(RPC_X_NULL_REF_POINTER);
4419 return FALSE;
4421 if(pDriverDirectory == NULL) {
4422 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
4423 SetLastError(ERROR_INVALID_USER_BUFFER);
4424 return FALSE;
4427 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
4428 /* add the Subdirectories */
4429 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
4430 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
4431 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
4432 return TRUE;
4436 /*****************************************************************************
4437 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4439 * Return the PATH for the Printer-Drivers (ANSI)
4441 * See GetPrinterDriverDirectoryW.
4443 * NOTES
4444 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4447 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4448 DWORD Level, LPBYTE pDriverDirectory,
4449 DWORD cbBuf, LPDWORD pcbNeeded)
4451 UNICODE_STRING nameW, environmentW;
4452 BOOL ret;
4453 DWORD pcbNeededW;
4454 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4455 WCHAR *driverDirectoryW = NULL;
4457 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4458 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4460 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4462 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4463 else nameW.Buffer = NULL;
4464 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4465 else environmentW.Buffer = NULL;
4467 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4468 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4469 if (ret) {
4470 DWORD needed;
4471 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4472 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4473 if(pcbNeeded)
4474 *pcbNeeded = needed;
4475 ret = (needed <= cbBuf) ? TRUE : FALSE;
4476 } else
4477 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4479 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4481 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4482 RtlFreeUnicodeString(&environmentW);
4483 RtlFreeUnicodeString(&nameW);
4485 return ret;
4488 /*****************************************************************************
4489 * AddPrinterDriverA [WINSPOOL.@]
4491 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4493 DRIVER_INFO_3A di3;
4494 HKEY hkeyDrivers, hkeyName;
4495 static CHAR empty[] = "",
4496 nullnull[] = "\0";
4498 TRACE("(%s,%d,%p)\n",debugstr_a(pName),level,pDriverInfo);
4500 if(level != 2 && level != 3) {
4501 SetLastError(ERROR_INVALID_LEVEL);
4502 return FALSE;
4504 if ((pName) && (pName[0])) {
4505 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
4506 SetLastError(ERROR_INVALID_PARAMETER);
4507 return FALSE;
4509 if(!pDriverInfo) {
4510 WARN("pDriverInfo == NULL\n");
4511 SetLastError(ERROR_INVALID_PARAMETER);
4512 return FALSE;
4515 if(level == 3)
4516 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
4517 else {
4518 memset(&di3, 0, sizeof(di3));
4519 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
4522 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
4523 !di3.pDataFile) {
4524 SetLastError(ERROR_INVALID_PARAMETER);
4525 return FALSE;
4528 if(!di3.pDefaultDataType) di3.pDefaultDataType = empty;
4529 if(!di3.pDependentFiles) di3.pDependentFiles = nullnull;
4530 if(!di3.pHelpFile) di3.pHelpFile = empty;
4531 if(!di3.pMonitorName) di3.pMonitorName = empty;
4533 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
4535 if(!hkeyDrivers) {
4536 ERR("Can't create Drivers key\n");
4537 return FALSE;
4540 if(level == 2) { /* apparently can't overwrite with level2 */
4541 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
4542 RegCloseKey(hkeyName);
4543 RegCloseKey(hkeyDrivers);
4544 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
4545 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
4546 return FALSE;
4549 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
4550 RegCloseKey(hkeyDrivers);
4551 ERR("Can't create Name key\n");
4552 return FALSE;
4554 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
4555 lstrlenA(di3.pConfigFile) + 1);
4556 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, lstrlenA(di3.pDataFile) + 1);
4557 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, lstrlenA(di3.pDriverPath) + 1);
4558 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
4559 sizeof(DWORD));
4560 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, lstrlenA(di3.pDefaultDataType));
4561 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
4562 (LPBYTE) di3.pDependentFiles, multi_sz_lenA(di3.pDependentFiles));
4563 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, lstrlenA(di3.pHelpFile) + 1);
4564 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, lstrlenA(di3.pMonitorName) + 1);
4565 RegCloseKey(hkeyName);
4566 RegCloseKey(hkeyDrivers);
4568 return TRUE;
4571 /*****************************************************************************
4572 * AddPrinterDriverW [WINSPOOL.@]
4574 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
4575 LPBYTE pDriverInfo)
4577 FIXME("(%s,%d,%p): stub\n",debugstr_w(printerName),
4578 level,pDriverInfo);
4579 return FALSE;
4582 /*****************************************************************************
4583 * AddPrintProcessorA [WINSPOOL.@]
4585 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4586 LPSTR pPrintProcessorName)
4588 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4589 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4590 return FALSE;
4593 /*****************************************************************************
4594 * AddPrintProcessorW [WINSPOOL.@]
4596 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4597 LPWSTR pPrintProcessorName)
4599 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4600 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4601 return FALSE;
4604 /*****************************************************************************
4605 * AddPrintProvidorA [WINSPOOL.@]
4607 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4609 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4610 return FALSE;
4613 /*****************************************************************************
4614 * AddPrintProvidorW [WINSPOOL.@]
4616 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4618 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4619 return FALSE;
4622 /*****************************************************************************
4623 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4625 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4626 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4628 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4629 pDevModeOutput, pDevModeInput);
4630 return 0;
4633 /*****************************************************************************
4634 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4636 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4637 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4639 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4640 pDevModeOutput, pDevModeInput);
4641 return 0;
4644 /*****************************************************************************
4645 * PrinterProperties [WINSPOOL.@]
4647 * Displays a dialog to set the properties of the printer.
4649 * RETURNS
4650 * nonzero on success or zero on failure
4652 * BUGS
4653 * implemented as stub only
4655 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4656 HANDLE hPrinter /* [in] handle to printer object */
4658 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4659 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4660 return FALSE;
4663 /*****************************************************************************
4664 * EnumJobsA [WINSPOOL.@]
4667 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4668 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4669 LPDWORD pcReturned)
4671 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4672 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4674 if(pcbNeeded) *pcbNeeded = 0;
4675 if(pcReturned) *pcReturned = 0;
4676 return FALSE;
4680 /*****************************************************************************
4681 * EnumJobsW [WINSPOOL.@]
4684 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4685 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4686 LPDWORD pcReturned)
4688 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4689 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4691 if(pcbNeeded) *pcbNeeded = 0;
4692 if(pcReturned) *pcReturned = 0;
4693 return FALSE;
4696 /*****************************************************************************
4697 * WINSPOOL_EnumPrinterDrivers [internal]
4699 * Delivers information about all printer drivers installed on the
4700 * localhost or a given server
4702 * RETURNS
4703 * nonzero on success or zero on failure. If the buffer for the returned
4704 * information is too small the function will return an error
4706 * BUGS
4707 * - only implemented for localhost, foreign hosts will return an error
4709 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
4710 DWORD Level, LPBYTE pDriverInfo,
4711 DWORD cbBuf, LPDWORD pcbNeeded,
4712 LPDWORD pcReturned, BOOL unicode)
4714 { HKEY hkeyDrivers;
4715 DWORD i, needed, number = 0, size = 0;
4716 WCHAR DriverNameW[255];
4717 PBYTE ptr;
4719 TRACE("%s,%s,%d,%p,%d,%d\n",
4720 debugstr_w(pName), debugstr_w(pEnvironment),
4721 Level, pDriverInfo, cbBuf, unicode);
4723 /* check for local drivers */
4724 if((pName) && (pName[0])) {
4725 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4726 SetLastError(ERROR_ACCESS_DENIED);
4727 return FALSE;
4730 /* check input parameter */
4731 if((Level < 1) || (Level > 3)) {
4732 ERR("unsupported level %d\n", Level);
4733 SetLastError(ERROR_INVALID_LEVEL);
4734 return FALSE;
4737 /* initialize return values */
4738 if(pDriverInfo)
4739 memset( pDriverInfo, 0, cbBuf);
4740 *pcbNeeded = 0;
4741 *pcReturned = 0;
4743 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
4744 if(!hkeyDrivers) {
4745 ERR("Can't open Drivers key\n");
4746 return FALSE;
4749 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
4750 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4751 RegCloseKey(hkeyDrivers);
4752 ERR("Can't query Drivers key\n");
4753 return FALSE;
4755 TRACE("Found %d Drivers\n", number);
4757 /* get size of single struct
4758 * unicode and ascii structure have the same size
4760 switch (Level) {
4761 case 1:
4762 size = sizeof(DRIVER_INFO_1A);
4763 break;
4764 case 2:
4765 size = sizeof(DRIVER_INFO_2A);
4766 break;
4767 case 3:
4768 size = sizeof(DRIVER_INFO_3A);
4769 break;
4772 /* calculate required buffer size */
4773 *pcbNeeded = size * number;
4775 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
4776 i < number;
4777 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
4778 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
4779 != ERROR_SUCCESS) {
4780 ERR("Can't enum key number %d\n", i);
4781 RegCloseKey(hkeyDrivers);
4782 return FALSE;
4784 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4785 pEnvironment, Level, ptr,
4786 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
4787 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4788 &needed, unicode)) {
4789 RegCloseKey(hkeyDrivers);
4790 return FALSE;
4792 (*pcbNeeded) += needed;
4795 RegCloseKey(hkeyDrivers);
4797 if(cbBuf < *pcbNeeded){
4798 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4799 return FALSE;
4802 *pcReturned = number;
4803 return TRUE;
4806 /*****************************************************************************
4807 * EnumPrinterDriversW [WINSPOOL.@]
4809 * see function EnumPrinterDrivers for RETURNS, BUGS
4811 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4812 LPBYTE pDriverInfo, DWORD cbBuf,
4813 LPDWORD pcbNeeded, LPDWORD pcReturned)
4815 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4816 cbBuf, pcbNeeded, pcReturned, TRUE);
4819 /*****************************************************************************
4820 * EnumPrinterDriversA [WINSPOOL.@]
4822 * see function EnumPrinterDrivers for RETURNS, BUGS
4824 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4825 LPBYTE pDriverInfo, DWORD cbBuf,
4826 LPDWORD pcbNeeded, LPDWORD pcReturned)
4827 { BOOL ret;
4828 UNICODE_STRING pNameW, pEnvironmentW;
4829 PWSTR pwstrNameW, pwstrEnvironmentW;
4831 pwstrNameW = asciitounicode(&pNameW, pName);
4832 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4834 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
4835 Level, pDriverInfo, cbBuf, pcbNeeded,
4836 pcReturned, FALSE);
4837 RtlFreeUnicodeString(&pNameW);
4838 RtlFreeUnicodeString(&pEnvironmentW);
4840 return ret;
4843 /******************************************************************************
4844 * EnumPortsA (WINSPOOL.@)
4846 * See EnumPortsW.
4849 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
4850 LPDWORD pcbNeeded, LPDWORD pcReturned)
4852 BOOL res;
4853 LPBYTE bufferW = NULL;
4854 LPWSTR nameW = NULL;
4855 DWORD needed = 0;
4856 DWORD numentries = 0;
4857 INT len;
4859 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
4860 cbBuf, pcbNeeded, pcReturned);
4862 /* convert servername to unicode */
4863 if (pName) {
4864 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
4865 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
4866 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
4868 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
4869 needed = cbBuf * sizeof(WCHAR);
4870 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
4871 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
4873 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
4874 if (pcbNeeded) needed = *pcbNeeded;
4875 /* HeapReAlloc return NULL, when bufferW was NULL */
4876 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
4877 HeapAlloc(GetProcessHeap(), 0, needed);
4879 /* Try again with the large Buffer */
4880 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
4882 needed = pcbNeeded ? *pcbNeeded : 0;
4883 numentries = pcReturned ? *pcReturned : 0;
4886 W2k require the buffersize from EnumPortsW also for EnumPortsA.
4887 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
4889 if (res) {
4890 /* EnumPortsW collected all Data. Parse them to caclulate ANSI-Size */
4891 DWORD entrysize = 0;
4892 DWORD index;
4893 LPSTR ptr;
4894 LPPORT_INFO_2W pi2w;
4895 LPPORT_INFO_2A pi2a;
4897 needed = 0;
4898 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
4900 /* First pass: calculate the size for all Entries */
4901 pi2w = (LPPORT_INFO_2W) bufferW;
4902 pi2a = (LPPORT_INFO_2A) pPorts;
4903 index = 0;
4904 while (index < numentries) {
4905 index++;
4906 needed += entrysize; /* PORT_INFO_?A */
4907 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
4909 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
4910 NULL, 0, NULL, NULL);
4911 if (Level > 1) {
4912 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
4913 NULL, 0, NULL, NULL);
4914 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
4915 NULL, 0, NULL, NULL);
4917 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
4918 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
4919 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
4922 /* check for errors and quit on failure */
4923 if (cbBuf < needed) {
4924 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4925 res = FALSE;
4926 goto cleanup;
4928 len = entrysize * numentries; /* room for all PORT_INFO_?A */
4929 ptr = (LPSTR) &pPorts[len]; /* room for strings */
4930 cbBuf -= len ; /* free Bytes in the user-Buffer */
4931 pi2w = (LPPORT_INFO_2W) bufferW;
4932 pi2a = (LPPORT_INFO_2A) pPorts;
4933 index = 0;
4934 /* Second Pass: Fill the User Buffer (if we have one) */
4935 while ((index < numentries) && pPorts) {
4936 index++;
4937 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
4938 pi2a->pPortName = ptr;
4939 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
4940 ptr, cbBuf , NULL, NULL);
4941 ptr += len;
4942 cbBuf -= len;
4943 if (Level > 1) {
4944 pi2a->pMonitorName = ptr;
4945 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
4946 ptr, cbBuf, NULL, NULL);
4947 ptr += len;
4948 cbBuf -= len;
4950 pi2a->pDescription = ptr;
4951 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
4952 ptr, cbBuf, NULL, NULL);
4953 ptr += len;
4954 cbBuf -= len;
4956 pi2a->fPortType = pi2w->fPortType;
4957 pi2a->Reserved = 0; /* documented: "must be zero" */
4960 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
4961 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
4962 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
4966 cleanup:
4967 if (pcbNeeded) *pcbNeeded = needed;
4968 if (pcReturned) *pcReturned = (res) ? numentries : 0;
4970 HeapFree(GetProcessHeap(), 0, nameW);
4971 HeapFree(GetProcessHeap(), 0, bufferW);
4973 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
4974 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
4976 return (res);
4980 /******************************************************************************
4981 * EnumPortsW (WINSPOOL.@)
4983 * Enumerate available Ports
4985 * PARAMS
4986 * name [I] Servername or NULL (local Computer)
4987 * level [I] Structure-Level (1 or 2)
4988 * buffer [O] PTR to Buffer that receives the Result
4989 * bufsize [I] Size of Buffer at buffer
4990 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
4991 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
4993 * RETURNS
4994 * Success: TRUE
4995 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
4999 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5001 DWORD needed = 0;
5002 DWORD numentries = 0;
5003 BOOL res = FALSE;
5005 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5006 cbBuf, pcbNeeded, pcReturned);
5008 if (pName && (pName[0])) {
5009 FIXME("not implemented for Server %s\n", debugstr_w(pName));
5010 SetLastError(ERROR_ACCESS_DENIED);
5011 goto emP_cleanup;
5014 /* Level is not checked in win9x */
5015 if (!Level || (Level > 2)) {
5016 WARN("level (%d) is ignored in win9x\n", Level);
5017 SetLastError(ERROR_INVALID_LEVEL);
5018 goto emP_cleanup;
5020 if (!pcbNeeded) {
5021 SetLastError(RPC_X_NULL_REF_POINTER);
5022 goto emP_cleanup;
5025 EnterCriticalSection(&monitor_handles_cs);
5026 monitor_loadall();
5028 /* Scan all local Ports */
5029 numentries = 0;
5030 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
5032 /* we calculated the needed buffersize. now do the error-checks */
5033 if (cbBuf < needed) {
5034 monitor_unloadall();
5035 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5036 goto emP_cleanup_cs;
5038 else if (!pPorts || !pcReturned) {
5039 monitor_unloadall();
5040 SetLastError(RPC_X_NULL_REF_POINTER);
5041 goto emP_cleanup_cs;
5044 /* Fill the Buffer */
5045 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
5046 res = TRUE;
5047 monitor_unloadall();
5049 emP_cleanup_cs:
5050 LeaveCriticalSection(&monitor_handles_cs);
5052 emP_cleanup:
5053 if (pcbNeeded) *pcbNeeded = needed;
5054 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5056 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5057 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5059 return (res);
5062 /******************************************************************************
5063 * GetDefaultPrinterW (WINSPOOL.@)
5065 * FIXME
5066 * This function must read the value from data 'device' of key
5067 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5069 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5071 BOOL retval = TRUE;
5072 DWORD insize, len;
5073 WCHAR *buffer, *ptr;
5075 if (!namesize)
5077 SetLastError(ERROR_INVALID_PARAMETER);
5078 return FALSE;
5081 /* make the buffer big enough for the stuff from the profile/registry,
5082 * the content must fit into the local buffer to compute the correct
5083 * size even if the extern buffer is too small or not given.
5084 * (20 for ,driver,port) */
5085 insize = *namesize;
5086 len = max(100, (insize + 20));
5087 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5089 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5091 SetLastError (ERROR_FILE_NOT_FOUND);
5092 retval = FALSE;
5093 goto end;
5095 TRACE("%s\n", debugstr_w(buffer));
5097 if ((ptr = strchrW(buffer, ',')) == NULL)
5099 SetLastError(ERROR_INVALID_NAME);
5100 retval = FALSE;
5101 goto end;
5104 *ptr = 0;
5105 *namesize = strlenW(buffer) + 1;
5106 if(!name || (*namesize > insize))
5108 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5109 retval = FALSE;
5110 goto end;
5112 strcpyW(name, buffer);
5114 end:
5115 HeapFree( GetProcessHeap(), 0, buffer);
5116 return retval;
5120 /******************************************************************************
5121 * GetDefaultPrinterA (WINSPOOL.@)
5123 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5125 BOOL retval = TRUE;
5126 DWORD insize = 0;
5127 WCHAR *bufferW = NULL;
5129 if (!namesize)
5131 SetLastError(ERROR_INVALID_PARAMETER);
5132 return FALSE;
5135 if(name && *namesize) {
5136 insize = *namesize;
5137 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5140 if(!GetDefaultPrinterW( bufferW, namesize)) {
5141 retval = FALSE;
5142 goto end;
5145 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5146 NULL, NULL);
5147 if (!*namesize)
5149 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5150 retval = FALSE;
5152 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5154 end:
5155 HeapFree( GetProcessHeap(), 0, bufferW);
5156 return retval;
5160 /******************************************************************************
5161 * SetDefaultPrinterW (WINSPOOL.204)
5163 * Set the Name of the Default Printer
5165 * PARAMS
5166 * pszPrinter [I] Name of the Printer or NULL
5168 * RETURNS
5169 * Success: True
5170 * Failure: FALSE
5172 * NOTES
5173 * When the Parameter is NULL or points to an Empty String and
5174 * a Default Printer was already present, then this Function changes nothing.
5175 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5176 * the First enumerated local Printer is used.
5179 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5182 TRACE("(%s)\n", debugstr_w(pszPrinter));
5184 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5185 return FALSE;
5188 /******************************************************************************
5189 * SetDefaultPrinterA (WINSPOOL.202)
5191 * See SetDefaultPrinterW.
5194 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5197 TRACE("(%s)\n", debugstr_a(pszPrinter));
5199 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5200 return FALSE;
5204 /******************************************************************************
5205 * SetPrinterDataExA (WINSPOOL.@)
5207 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5208 LPCSTR pValueName, DWORD Type,
5209 LPBYTE pData, DWORD cbData)
5211 HKEY hkeyPrinter, hkeySubkey;
5212 DWORD ret;
5214 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5215 debugstr_a(pValueName), Type, pData, cbData);
5217 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5218 != ERROR_SUCCESS)
5219 return ret;
5221 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5222 != ERROR_SUCCESS) {
5223 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5224 RegCloseKey(hkeyPrinter);
5225 return ret;
5227 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5228 RegCloseKey(hkeySubkey);
5229 RegCloseKey(hkeyPrinter);
5230 return ret;
5233 /******************************************************************************
5234 * SetPrinterDataExW (WINSPOOL.@)
5236 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5237 LPCWSTR pValueName, DWORD Type,
5238 LPBYTE pData, DWORD cbData)
5240 HKEY hkeyPrinter, hkeySubkey;
5241 DWORD ret;
5243 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5244 debugstr_w(pValueName), Type, pData, cbData);
5246 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5247 != ERROR_SUCCESS)
5248 return ret;
5250 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5251 != ERROR_SUCCESS) {
5252 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5253 RegCloseKey(hkeyPrinter);
5254 return ret;
5256 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5257 RegCloseKey(hkeySubkey);
5258 RegCloseKey(hkeyPrinter);
5259 return ret;
5262 /******************************************************************************
5263 * SetPrinterDataA (WINSPOOL.@)
5265 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5266 LPBYTE pData, DWORD cbData)
5268 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5269 pData, cbData);
5272 /******************************************************************************
5273 * SetPrinterDataW (WINSPOOL.@)
5275 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5276 LPBYTE pData, DWORD cbData)
5278 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5279 pData, cbData);
5282 /******************************************************************************
5283 * GetPrinterDataExA (WINSPOOL.@)
5285 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5286 LPCSTR pValueName, LPDWORD pType,
5287 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5289 HKEY hkeyPrinter, hkeySubkey;
5290 DWORD ret;
5292 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5293 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5294 pcbNeeded);
5296 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5297 != ERROR_SUCCESS)
5298 return ret;
5300 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5301 != ERROR_SUCCESS) {
5302 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5303 RegCloseKey(hkeyPrinter);
5304 return ret;
5306 *pcbNeeded = nSize;
5307 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5308 RegCloseKey(hkeySubkey);
5309 RegCloseKey(hkeyPrinter);
5310 return ret;
5313 /******************************************************************************
5314 * GetPrinterDataExW (WINSPOOL.@)
5316 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5317 LPCWSTR pValueName, LPDWORD pType,
5318 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5320 HKEY hkeyPrinter, hkeySubkey;
5321 DWORD ret;
5323 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5324 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5325 pcbNeeded);
5327 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5328 != ERROR_SUCCESS)
5329 return ret;
5331 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5332 != ERROR_SUCCESS) {
5333 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5334 RegCloseKey(hkeyPrinter);
5335 return ret;
5337 *pcbNeeded = nSize;
5338 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5339 RegCloseKey(hkeySubkey);
5340 RegCloseKey(hkeyPrinter);
5341 return ret;
5344 /******************************************************************************
5345 * GetPrinterDataA (WINSPOOL.@)
5347 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5348 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5350 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5351 pData, nSize, pcbNeeded);
5354 /******************************************************************************
5355 * GetPrinterDataW (WINSPOOL.@)
5357 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5358 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5360 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5361 pData, nSize, pcbNeeded);
5364 /*******************************************************************************
5365 * EnumPrinterDataExW [WINSPOOL.@]
5367 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5368 LPBYTE pEnumValues, DWORD cbEnumValues,
5369 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5371 HKEY hkPrinter, hkSubKey;
5372 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5373 cbValueNameLen, cbMaxValueLen, cbValueLen,
5374 cbBufSize, dwType;
5375 LPWSTR lpValueName;
5376 HANDLE hHeap;
5377 PBYTE lpValue;
5378 PPRINTER_ENUM_VALUESW ppev;
5380 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5382 if (pKeyName == NULL || *pKeyName == 0)
5383 return ERROR_INVALID_PARAMETER;
5385 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5386 if (ret != ERROR_SUCCESS)
5388 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5389 hPrinter, ret);
5390 return ret;
5393 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5394 if (ret != ERROR_SUCCESS)
5396 r = RegCloseKey (hkPrinter);
5397 if (r != ERROR_SUCCESS)
5398 WARN ("RegCloseKey returned %i\n", r);
5399 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5400 debugstr_w (pKeyName), ret);
5401 return ret;
5404 ret = RegCloseKey (hkPrinter);
5405 if (ret != ERROR_SUCCESS)
5407 ERR ("RegCloseKey returned %i\n", ret);
5408 r = RegCloseKey (hkSubKey);
5409 if (r != ERROR_SUCCESS)
5410 WARN ("RegCloseKey returned %i\n", r);
5411 return ret;
5414 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5415 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5416 if (ret != ERROR_SUCCESS)
5418 r = RegCloseKey (hkSubKey);
5419 if (r != ERROR_SUCCESS)
5420 WARN ("RegCloseKey returned %i\n", r);
5421 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5422 return ret;
5425 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5426 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5428 if (cValues == 0) /* empty key */
5430 r = RegCloseKey (hkSubKey);
5431 if (r != ERROR_SUCCESS)
5432 WARN ("RegCloseKey returned %i\n", r);
5433 *pcbEnumValues = *pnEnumValues = 0;
5434 return ERROR_SUCCESS;
5437 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5439 hHeap = GetProcessHeap ();
5440 if (hHeap == NULL)
5442 ERR ("GetProcessHeap failed\n");
5443 r = RegCloseKey (hkSubKey);
5444 if (r != ERROR_SUCCESS)
5445 WARN ("RegCloseKey returned %i\n", r);
5446 return ERROR_OUTOFMEMORY;
5449 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5450 if (lpValueName == NULL)
5452 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5453 r = RegCloseKey (hkSubKey);
5454 if (r != ERROR_SUCCESS)
5455 WARN ("RegCloseKey returned %i\n", r);
5456 return ERROR_OUTOFMEMORY;
5459 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5460 if (lpValue == NULL)
5462 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5463 if (HeapFree (hHeap, 0, lpValueName) == 0)
5464 WARN ("HeapFree failed with code %i\n", GetLastError ());
5465 r = RegCloseKey (hkSubKey);
5466 if (r != ERROR_SUCCESS)
5467 WARN ("RegCloseKey returned %i\n", r);
5468 return ERROR_OUTOFMEMORY;
5471 TRACE ("pass 1: calculating buffer required for all names and values\n");
5473 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5475 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5477 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5479 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5480 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5481 NULL, NULL, lpValue, &cbValueLen);
5482 if (ret != ERROR_SUCCESS)
5484 if (HeapFree (hHeap, 0, lpValue) == 0)
5485 WARN ("HeapFree failed with code %i\n", GetLastError ());
5486 if (HeapFree (hHeap, 0, lpValueName) == 0)
5487 WARN ("HeapFree failed with code %i\n", GetLastError ());
5488 r = RegCloseKey (hkSubKey);
5489 if (r != ERROR_SUCCESS)
5490 WARN ("RegCloseKey returned %i\n", r);
5491 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5492 return ret;
5495 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5496 debugstr_w (lpValueName), dwIndex,
5497 cbValueNameLen + 1, cbValueLen);
5499 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5500 cbBufSize += cbValueLen;
5503 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5505 *pcbEnumValues = cbBufSize;
5506 *pnEnumValues = cValues;
5508 if (cbEnumValues < cbBufSize) /* buffer too small */
5510 if (HeapFree (hHeap, 0, lpValue) == 0)
5511 WARN ("HeapFree failed with code %i\n", GetLastError ());
5512 if (HeapFree (hHeap, 0, lpValueName) == 0)
5513 WARN ("HeapFree failed with code %i\n", GetLastError ());
5514 r = RegCloseKey (hkSubKey);
5515 if (r != ERROR_SUCCESS)
5516 WARN ("RegCloseKey returned %i\n", r);
5517 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5518 return ERROR_MORE_DATA;
5521 TRACE ("pass 2: copying all names and values to buffer\n");
5523 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5524 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5526 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5528 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5529 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5530 NULL, &dwType, lpValue, &cbValueLen);
5531 if (ret != ERROR_SUCCESS)
5533 if (HeapFree (hHeap, 0, lpValue) == 0)
5534 WARN ("HeapFree failed with code %i\n", GetLastError ());
5535 if (HeapFree (hHeap, 0, lpValueName) == 0)
5536 WARN ("HeapFree failed with code %i\n", GetLastError ());
5537 r = RegCloseKey (hkSubKey);
5538 if (r != ERROR_SUCCESS)
5539 WARN ("RegCloseKey returned %i\n", r);
5540 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5541 return ret;
5544 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5545 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5546 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5547 pEnumValues += cbValueNameLen;
5549 /* return # of *bytes* (including trailing \0), not # of chars */
5550 ppev[dwIndex].cbValueName = cbValueNameLen;
5552 ppev[dwIndex].dwType = dwType;
5554 memcpy (pEnumValues, lpValue, cbValueLen);
5555 ppev[dwIndex].pData = pEnumValues;
5556 pEnumValues += cbValueLen;
5558 ppev[dwIndex].cbData = cbValueLen;
5560 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5561 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5564 if (HeapFree (hHeap, 0, lpValue) == 0)
5566 ret = GetLastError ();
5567 ERR ("HeapFree failed with code %i\n", ret);
5568 if (HeapFree (hHeap, 0, lpValueName) == 0)
5569 WARN ("HeapFree failed with code %i\n", GetLastError ());
5570 r = RegCloseKey (hkSubKey);
5571 if (r != ERROR_SUCCESS)
5572 WARN ("RegCloseKey returned %i\n", r);
5573 return ret;
5576 if (HeapFree (hHeap, 0, lpValueName) == 0)
5578 ret = GetLastError ();
5579 ERR ("HeapFree failed with code %i\n", ret);
5580 r = RegCloseKey (hkSubKey);
5581 if (r != ERROR_SUCCESS)
5582 WARN ("RegCloseKey returned %i\n", r);
5583 return ret;
5586 ret = RegCloseKey (hkSubKey);
5587 if (ret != ERROR_SUCCESS)
5589 ERR ("RegCloseKey returned %i\n", ret);
5590 return ret;
5593 return ERROR_SUCCESS;
5596 /*******************************************************************************
5597 * EnumPrinterDataExA [WINSPOOL.@]
5599 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5600 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5601 * what Windows 2000 SP1 does.
5604 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5605 LPBYTE pEnumValues, DWORD cbEnumValues,
5606 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5608 INT len;
5609 LPWSTR pKeyNameW;
5610 DWORD ret, dwIndex, dwBufSize;
5611 HANDLE hHeap;
5612 LPSTR pBuffer;
5614 TRACE ("%p %s\n", hPrinter, pKeyName);
5616 if (pKeyName == NULL || *pKeyName == 0)
5617 return ERROR_INVALID_PARAMETER;
5619 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5620 if (len == 0)
5622 ret = GetLastError ();
5623 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5624 return ret;
5627 hHeap = GetProcessHeap ();
5628 if (hHeap == NULL)
5630 ERR ("GetProcessHeap failed\n");
5631 return ERROR_OUTOFMEMORY;
5634 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5635 if (pKeyNameW == NULL)
5637 ERR ("Failed to allocate %i bytes from process heap\n",
5638 (LONG)(len * sizeof (WCHAR)));
5639 return ERROR_OUTOFMEMORY;
5642 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5644 ret = GetLastError ();
5645 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5646 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5647 WARN ("HeapFree failed with code %i\n", GetLastError ());
5648 return ret;
5651 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5652 pcbEnumValues, pnEnumValues);
5653 if (ret != ERROR_SUCCESS)
5655 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5656 WARN ("HeapFree failed with code %i\n", GetLastError ());
5657 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5658 return ret;
5661 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5663 ret = GetLastError ();
5664 ERR ("HeapFree failed with code %i\n", ret);
5665 return ret;
5668 if (*pnEnumValues == 0) /* empty key */
5669 return ERROR_SUCCESS;
5671 dwBufSize = 0;
5672 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5674 PPRINTER_ENUM_VALUESW ppev =
5675 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5677 if (dwBufSize < ppev->cbValueName)
5678 dwBufSize = ppev->cbValueName;
5680 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5681 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5682 dwBufSize = ppev->cbData;
5685 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5687 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5688 if (pBuffer == NULL)
5690 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5691 return ERROR_OUTOFMEMORY;
5694 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5696 PPRINTER_ENUM_VALUESW ppev =
5697 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5699 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5700 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5701 NULL);
5702 if (len == 0)
5704 ret = GetLastError ();
5705 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5706 if (HeapFree (hHeap, 0, pBuffer) == 0)
5707 WARN ("HeapFree failed with code %i\n", GetLastError ());
5708 return ret;
5711 memcpy (ppev->pValueName, pBuffer, len);
5713 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5715 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5716 ppev->dwType != REG_MULTI_SZ)
5717 continue;
5719 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5720 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5721 if (len == 0)
5723 ret = GetLastError ();
5724 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5725 if (HeapFree (hHeap, 0, pBuffer) == 0)
5726 WARN ("HeapFree failed with code %i\n", GetLastError ());
5727 return ret;
5730 memcpy (ppev->pData, pBuffer, len);
5732 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5733 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5736 if (HeapFree (hHeap, 0, pBuffer) == 0)
5738 ret = GetLastError ();
5739 ERR ("HeapFree failed with code %i\n", ret);
5740 return ret;
5743 return ERROR_SUCCESS;
5746 /******************************************************************************
5747 * AbortPrinter (WINSPOOL.@)
5749 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5751 FIXME("(%p), stub!\n", hPrinter);
5752 return TRUE;
5755 /******************************************************************************
5756 * AddPortA (WINSPOOL.@)
5758 * See AddPortW.
5761 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5763 LPWSTR nameW = NULL;
5764 LPWSTR monitorW = NULL;
5765 DWORD len;
5766 BOOL res;
5768 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
5770 if (pName) {
5771 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5772 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5773 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5776 if (pMonitorName) {
5777 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5778 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5779 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5781 res = AddPortW(nameW, hWnd, monitorW);
5782 HeapFree(GetProcessHeap(), 0, nameW);
5783 HeapFree(GetProcessHeap(), 0, monitorW);
5784 return res;
5787 /******************************************************************************
5788 * AddPortW (WINSPOOL.@)
5790 * Add a Port for a specific Monitor
5792 * PARAMS
5793 * pName [I] Servername or NULL (local Computer)
5794 * hWnd [I] Handle to parent Window for the Dialog-Box
5795 * pMonitorName [I] Name of the Monitor that manage the Port
5797 * RETURNS
5798 * Success: TRUE
5799 * Failure: FALSE
5802 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5804 monitor_t * pm;
5805 DWORD res = ROUTER_UNKNOWN;
5807 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
5809 if (pName && pName[0]) {
5810 SetLastError(ERROR_INVALID_PARAMETER);
5811 return FALSE;
5814 if (!pMonitorName) {
5815 SetLastError(RPC_X_NULL_REF_POINTER);
5816 return FALSE;
5819 /* an empty Monitorname is Invalid */
5820 if (!pMonitorName[0]) goto cleanup;
5822 pm = monitor_load(pMonitorName, NULL);
5823 if (pm && pm->monitor) {
5824 if (pm->monitor->pfnAddPort != NULL) {
5825 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
5826 TRACE("got %d with %d\n", res, GetLastError());
5828 else if (pm->monitor->pfnXcvOpenPort != NULL)
5830 FIXME("XcvOpenPort not implemented (dwMonitorSize: %d)\n", pm->dwMonitorSize);
5832 /* invalidate cached PORT_INFO_2W */
5833 if (res == ROUTER_SUCCESS) monitor_flush(pm);
5835 monitor_unload(pm);
5837 cleanup:
5838 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
5839 if (res == ROUTER_UNKNOWN) SetLastError(ERROR_NOT_SUPPORTED);
5840 TRACE("returning %d with %d\n", (res == ROUTER_SUCCESS), GetLastError());
5841 return (res == ROUTER_SUCCESS);
5844 /******************************************************************************
5845 * AddPortExA (WINSPOOL.@)
5847 * See AddPortExW.
5850 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
5852 FIXME("(%p, %s, %d, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
5853 lpBuffer, debugstr_a(lpMonitorName));
5854 return FALSE;
5857 /******************************************************************************
5858 * AddPortExW (WINSPOOL.@)
5860 * Add a Port for a specific Monitor, without presenting a user interface
5862 * PARAMS
5863 * hMonitor [I] Handle from InitializePrintMonitor2()
5864 * pName [I] Servername or NULL (local Computer)
5865 * Level [I] Structure-Level (1 or 2) for lpBuffer
5866 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
5867 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
5869 * RETURNS
5870 * Success: TRUE
5871 * Failure: FALSE
5873 * BUGS
5874 * only a Stub
5877 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
5879 FIXME("(%p, %s, %d, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
5880 lpBuffer, debugstr_w(lpMonitorName));
5881 return FALSE;
5884 /******************************************************************************
5885 * AddPrinterConnectionA (WINSPOOL.@)
5887 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
5889 FIXME("%s\n", debugstr_a(pName));
5890 return FALSE;
5893 /******************************************************************************
5894 * AddPrinterConnectionW (WINSPOOL.@)
5896 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
5898 FIXME("%s\n", debugstr_w(pName));
5899 return FALSE;
5902 /******************************************************************************
5903 * AddPrinterDriverExW (WINSPOOL.@)
5905 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
5906 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5908 FIXME("%s %d %p %d\n", debugstr_w(pName),
5909 Level, pDriverInfo, dwFileCopyFlags);
5910 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5911 return FALSE;
5914 /******************************************************************************
5915 * AddPrinterDriverExA (WINSPOOL.@)
5917 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
5918 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5920 FIXME("%s %d %p %d\n", debugstr_a(pName),
5921 Level, pDriverInfo, dwFileCopyFlags);
5922 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5923 return FALSE;
5926 /******************************************************************************
5927 * ConfigurePortA (WINSPOOL.@)
5929 * See ConfigurePortW.
5932 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
5934 LPWSTR nameW = NULL;
5935 LPWSTR portW = NULL;
5936 INT len;
5937 DWORD res;
5939 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
5941 /* convert servername to unicode */
5942 if (pName) {
5943 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5944 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5945 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5948 /* convert portname to unicode */
5949 if (pPortName) {
5950 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
5951 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5952 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
5955 res = ConfigurePortW(nameW, hWnd, portW);
5956 HeapFree(GetProcessHeap(), 0, nameW);
5957 HeapFree(GetProcessHeap(), 0, portW);
5958 return res;
5961 /******************************************************************************
5962 * ConfigurePortW (WINSPOOL.@)
5964 * Display the Configuration-Dialog for a specific Port
5966 * PARAMS
5967 * pName [I] Servername or NULL (local Computer)
5968 * hWnd [I] Handle to parent Window for the Dialog-Box
5969 * pPortName [I] Name of the Port, that should be configured
5971 * RETURNS
5972 * Success: TRUE
5973 * Failure: FALSE
5976 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
5978 monitor_t * pm;
5979 DWORD res = ROUTER_UNKNOWN;
5981 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
5983 if (pName && pName[0]) {
5984 SetLastError(ERROR_INVALID_PARAMETER);
5985 return FALSE;
5988 if (!pPortName) {
5989 SetLastError(RPC_X_NULL_REF_POINTER);
5990 return FALSE;
5993 /* an empty Portname is Invalid, but can popup a Dialog */
5994 if (!pPortName[0]) goto cleanup;
5997 pm = monitor_load_by_port(pPortName);
5998 if (pm && pm->monitor) {
5999 if (pm->monitor->pfnConfigurePort != NULL) {
6000 TRACE("Using %s for %s:\n", debugstr_w(pm->name), debugstr_w(pPortName));
6001 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6002 TRACE("got %d with %d\n", res, GetLastError());
6004 else
6006 FIXME("XcvOpenPort not implemented (dwMonitorSize: %d)\n", pm->dwMonitorSize);
6009 monitor_unload(pm);
6011 cleanup:
6012 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6013 if (res == ROUTER_UNKNOWN) SetLastError(ERROR_NOT_SUPPORTED);
6014 TRACE("returning %d with %d\n", (res == ROUTER_SUCCESS), GetLastError());
6015 return (res == ROUTER_SUCCESS);
6018 /******************************************************************************
6019 * ConnectToPrinterDlg (WINSPOOL.@)
6021 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6023 FIXME("%p %x\n", hWnd, Flags);
6024 return NULL;
6027 /******************************************************************************
6028 * DeletePrinterConnectionA (WINSPOOL.@)
6030 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6032 FIXME("%s\n", debugstr_a(pName));
6033 return TRUE;
6036 /******************************************************************************
6037 * DeletePrinterConnectionW (WINSPOOL.@)
6039 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6041 FIXME("%s\n", debugstr_w(pName));
6042 return TRUE;
6045 /******************************************************************************
6046 * DeletePrinterDriverExW (WINSPOOL.@)
6048 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6049 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6051 HKEY hkey_drivers;
6052 BOOL ret = FALSE;
6054 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6055 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6057 if(pName && pName[0])
6059 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6060 SetLastError(ERROR_INVALID_PARAMETER);
6061 return FALSE;
6064 if(dwDeleteFlag)
6066 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6067 SetLastError(ERROR_INVALID_PARAMETER);
6068 return FALSE;
6071 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6073 if(!hkey_drivers)
6075 ERR("Can't open drivers key\n");
6076 return FALSE;
6079 if(WINSPOOL_SHDeleteKeyW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6080 ret = TRUE;
6082 RegCloseKey(hkey_drivers);
6084 return ret;
6087 /******************************************************************************
6088 * DeletePrinterDriverExA (WINSPOOL.@)
6090 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6091 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6093 UNICODE_STRING NameW, EnvW, DriverW;
6094 BOOL ret;
6096 asciitounicode(&NameW, pName);
6097 asciitounicode(&EnvW, pEnvironment);
6098 asciitounicode(&DriverW, pDriverName);
6100 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6102 RtlFreeUnicodeString(&DriverW);
6103 RtlFreeUnicodeString(&EnvW);
6104 RtlFreeUnicodeString(&NameW);
6106 return ret;
6109 /******************************************************************************
6110 * DeletePrinterDataExW (WINSPOOL.@)
6112 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6113 LPCWSTR pValueName)
6115 FIXME("%p %s %s\n", hPrinter,
6116 debugstr_w(pKeyName), debugstr_w(pValueName));
6117 return ERROR_INVALID_PARAMETER;
6120 /******************************************************************************
6121 * DeletePrinterDataExA (WINSPOOL.@)
6123 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6124 LPCSTR pValueName)
6126 FIXME("%p %s %s\n", hPrinter,
6127 debugstr_a(pKeyName), debugstr_a(pValueName));
6128 return ERROR_INVALID_PARAMETER;
6131 /******************************************************************************
6132 * DeletePrintProcessorA (WINSPOOL.@)
6134 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6136 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6137 debugstr_a(pPrintProcessorName));
6138 return TRUE;
6141 /******************************************************************************
6142 * DeletePrintProcessorW (WINSPOOL.@)
6144 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6146 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6147 debugstr_w(pPrintProcessorName));
6148 return TRUE;
6151 /******************************************************************************
6152 * DeletePrintProvidorA (WINSPOOL.@)
6154 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6156 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6157 debugstr_a(pPrintProviderName));
6158 return TRUE;
6161 /******************************************************************************
6162 * DeletePrintProvidorW (WINSPOOL.@)
6164 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6166 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6167 debugstr_w(pPrintProviderName));
6168 return TRUE;
6171 /******************************************************************************
6172 * EnumFormsA (WINSPOOL.@)
6174 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6175 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6177 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6178 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6179 return FALSE;
6182 /******************************************************************************
6183 * EnumFormsW (WINSPOOL.@)
6185 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6186 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6188 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6189 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6190 return FALSE;
6193 /*****************************************************************************
6194 * EnumMonitorsA [WINSPOOL.@]
6196 * See EnumMonitorsW.
6199 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6200 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6202 BOOL res;
6203 LPBYTE bufferW = NULL;
6204 LPWSTR nameW = NULL;
6205 DWORD needed = 0;
6206 DWORD numentries = 0;
6207 INT len;
6209 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6210 cbBuf, pcbNeeded, pcReturned);
6212 /* convert servername to unicode */
6213 if (pName) {
6214 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6215 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6216 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6218 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6219 needed = cbBuf * sizeof(WCHAR);
6220 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6221 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6223 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6224 if (pcbNeeded) needed = *pcbNeeded;
6225 /* HeapReAlloc return NULL, when bufferW was NULL */
6226 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6227 HeapAlloc(GetProcessHeap(), 0, needed);
6229 /* Try again with the large Buffer */
6230 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6232 numentries = pcReturned ? *pcReturned : 0;
6233 needed = 0;
6235 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6236 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6238 if (res) {
6239 /* EnumMonitorsW collected all Data. Parse them to caclulate ANSI-Size */
6240 DWORD entrysize = 0;
6241 DWORD index;
6242 LPSTR ptr;
6243 LPMONITOR_INFO_2W mi2w;
6244 LPMONITOR_INFO_2A mi2a;
6246 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6247 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6249 /* First pass: calculate the size for all Entries */
6250 mi2w = (LPMONITOR_INFO_2W) bufferW;
6251 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6252 index = 0;
6253 while (index < numentries) {
6254 index++;
6255 needed += entrysize; /* MONITOR_INFO_?A */
6256 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6258 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6259 NULL, 0, NULL, NULL);
6260 if (Level > 1) {
6261 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6262 NULL, 0, NULL, NULL);
6263 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6264 NULL, 0, NULL, NULL);
6266 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6267 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6268 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6271 /* check for errors and quit on failure */
6272 if (cbBuf < needed) {
6273 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6274 res = FALSE;
6275 goto emA_cleanup;
6277 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6278 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6279 cbBuf -= len ; /* free Bytes in the user-Buffer */
6280 mi2w = (LPMONITOR_INFO_2W) bufferW;
6281 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6282 index = 0;
6283 /* Second Pass: Fill the User Buffer (if we have one) */
6284 while ((index < numentries) && pMonitors) {
6285 index++;
6286 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6287 mi2a->pName = ptr;
6288 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6289 ptr, cbBuf , NULL, NULL);
6290 ptr += len;
6291 cbBuf -= len;
6292 if (Level > 1) {
6293 mi2a->pEnvironment = ptr;
6294 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6295 ptr, cbBuf, NULL, NULL);
6296 ptr += len;
6297 cbBuf -= len;
6299 mi2a->pDLLName = ptr;
6300 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6301 ptr, cbBuf, NULL, NULL);
6302 ptr += len;
6303 cbBuf -= len;
6305 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6306 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6307 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6310 emA_cleanup:
6311 if (pcbNeeded) *pcbNeeded = needed;
6312 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6314 HeapFree(GetProcessHeap(), 0, nameW);
6315 HeapFree(GetProcessHeap(), 0, bufferW);
6317 TRACE("returning %d with %d (%d byte for %d entries)\n",
6318 (res), GetLastError(), needed, numentries);
6320 return (res);
6324 /*****************************************************************************
6325 * EnumMonitorsW [WINSPOOL.@]
6327 * Enumerate available Port-Monitors
6329 * PARAMS
6330 * pName [I] Servername or NULL (local Computer)
6331 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6332 * pMonitors [O] PTR to Buffer that receives the Result
6333 * cbBuf [I] Size of Buffer at pMonitors
6334 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6335 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6337 * RETURNS
6338 * Success: TRUE
6339 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6341 * NOTES
6342 * Windows reads the Registry once and cache the Results.
6344 *| Language-Monitors are also installed in the same Registry-Location but
6345 *| they are filtered in Windows (not returned by EnumMonitors).
6346 *| We do no filtering to simplify our Code.
6349 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6350 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6352 DWORD needed = 0;
6353 DWORD numentries = 0;
6354 BOOL res = FALSE;
6356 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6357 cbBuf, pcbNeeded, pcReturned);
6359 if (pName && (lstrlenW(pName))) {
6360 FIXME("for Server %s not implemented\n", debugstr_w(pName));
6361 SetLastError(ERROR_ACCESS_DENIED);
6362 goto emW_cleanup;
6365 /* Level is not checked in win9x */
6366 if (!Level || (Level > 2)) {
6367 WARN("level (%d) is ignored in win9x\n", Level);
6368 SetLastError(ERROR_INVALID_LEVEL);
6369 goto emW_cleanup;
6371 if (!pcbNeeded) {
6372 SetLastError(RPC_X_NULL_REF_POINTER);
6373 goto emW_cleanup;
6376 /* Scan all Monitor-Keys */
6377 numentries = 0;
6378 needed = get_local_monitors(Level, NULL, 0, &numentries);
6380 /* we calculated the needed buffersize. now do the error-checks */
6381 if (cbBuf < needed) {
6382 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6383 goto emW_cleanup;
6385 else if (!pMonitors || !pcReturned) {
6386 SetLastError(RPC_X_NULL_REF_POINTER);
6387 goto emW_cleanup;
6390 /* fill the Buffer with the Monitor-Keys */
6391 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
6392 res = TRUE;
6394 emW_cleanup:
6395 if (pcbNeeded) *pcbNeeded = needed;
6396 if (pcReturned) *pcReturned = numentries;
6398 TRACE("returning %d with %d (%d byte for %d entries)\n",
6399 res, GetLastError(), needed, numentries);
6401 return (res);
6404 /******************************************************************************
6405 * XcvDataW (WINSPOOL.@)
6407 * Notes:
6408 * There doesn't seem to be an A version...
6410 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6411 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6412 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6414 FIXME("%p %s %p %d %p %d %p %p\n", hXcv, debugstr_w(pszDataName),
6415 pInputData, cbInputData, pOutputData,
6416 cbOutputData, pcbOutputNeeded, pdwStatus);
6417 return FALSE;
6420 /*****************************************************************************
6421 * EnumPrinterDataA [WINSPOOL.@]
6424 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6425 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6426 DWORD cbData, LPDWORD pcbData )
6428 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6429 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6430 return ERROR_NO_MORE_ITEMS;
6433 /*****************************************************************************
6434 * EnumPrinterDataW [WINSPOOL.@]
6437 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6438 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6439 DWORD cbData, LPDWORD pcbData )
6441 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6442 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6443 return ERROR_NO_MORE_ITEMS;
6446 /*****************************************************************************
6447 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6450 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6451 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6452 LPDWORD pcbNeeded, LPDWORD pcReturned)
6454 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6455 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6456 pcbNeeded, pcReturned);
6457 return FALSE;
6460 /*****************************************************************************
6461 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6464 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6465 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6466 LPDWORD pcbNeeded, LPDWORD pcReturned)
6468 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6469 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6470 pcbNeeded, pcReturned);
6471 return FALSE;
6474 /*****************************************************************************
6475 * EnumPrintProcessorsA [WINSPOOL.@]
6478 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6479 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
6481 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
6482 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
6483 return FALSE;
6486 /*****************************************************************************
6487 * EnumPrintProcessorsW [WINSPOOL.@]
6490 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
6491 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
6493 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6494 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
6495 cbBuf, pcbNeeded, pcbReturned);
6496 return FALSE;
6499 /*****************************************************************************
6500 * ExtDeviceMode [WINSPOOL.@]
6503 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
6504 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
6505 DWORD fMode)
6507 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
6508 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
6509 debugstr_a(pProfile), fMode);
6510 return -1;
6513 /*****************************************************************************
6514 * FindClosePrinterChangeNotification [WINSPOOL.@]
6517 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
6519 FIXME("Stub: %p\n", hChange);
6520 return TRUE;
6523 /*****************************************************************************
6524 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6527 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
6528 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
6530 FIXME("Stub: %p %x %x %p\n",
6531 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
6532 return INVALID_HANDLE_VALUE;
6535 /*****************************************************************************
6536 * FindNextPrinterChangeNotification [WINSPOOL.@]
6539 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
6540 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
6542 FIXME("Stub: %p %p %p %p\n",
6543 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
6544 return FALSE;
6547 /*****************************************************************************
6548 * FreePrinterNotifyInfo [WINSPOOL.@]
6551 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
6553 FIXME("Stub: %p\n", pPrinterNotifyInfo);
6554 return TRUE;
6557 /*****************************************************************************
6558 * string_to_buf
6560 * Copies a unicode string into a buffer. The buffer will either contain unicode or
6561 * ansi depending on the unicode parameter.
6563 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
6565 if(!str)
6567 *size = 0;
6568 return TRUE;
6571 if(unicode)
6573 *size = (strlenW(str) + 1) * sizeof(WCHAR);
6574 if(*size <= cb)
6576 memcpy(ptr, str, *size);
6577 return TRUE;
6579 return FALSE;
6581 else
6583 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
6584 if(*size <= cb)
6586 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
6587 return TRUE;
6589 return FALSE;
6593 /*****************************************************************************
6594 * get_job_info_1
6596 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
6597 LPDWORD pcbNeeded, BOOL unicode)
6599 DWORD size, left = cbBuf;
6600 BOOL space = (cbBuf > 0);
6601 LPBYTE ptr = buf;
6603 *pcbNeeded = 0;
6605 if(space)
6607 ji1->JobId = job->job_id;
6610 string_to_buf(job->document_title, ptr, left, &size, unicode);
6611 if(space && size <= left)
6613 ji1->pDocument = (LPWSTR)ptr;
6614 ptr += size;
6615 left -= size;
6617 else
6618 space = FALSE;
6619 *pcbNeeded += size;
6621 return space;
6624 /*****************************************************************************
6625 * get_job_info_2
6627 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
6628 LPDWORD pcbNeeded, BOOL unicode)
6630 DWORD size, left = cbBuf;
6631 BOOL space = (cbBuf > 0);
6632 LPBYTE ptr = buf;
6634 *pcbNeeded = 0;
6636 if(space)
6638 ji2->JobId = job->job_id;
6641 string_to_buf(job->document_title, ptr, left, &size, unicode);
6642 if(space && size <= left)
6644 ji2->pDocument = (LPWSTR)ptr;
6645 ptr += size;
6646 left -= size;
6648 else
6649 space = FALSE;
6650 *pcbNeeded += size;
6652 return space;
6655 /*****************************************************************************
6656 * get_job_info
6658 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6659 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
6661 BOOL ret = FALSE;
6662 DWORD needed = 0, size;
6663 job_t *job;
6664 LPBYTE ptr = pJob;
6666 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
6668 EnterCriticalSection(&printer_handles_cs);
6669 job = get_job(hPrinter, JobId);
6670 if(!job)
6671 goto end;
6673 switch(Level)
6675 case 1:
6676 size = sizeof(JOB_INFO_1W);
6677 if(cbBuf >= size)
6679 cbBuf -= size;
6680 ptr += size;
6681 memset(pJob, 0, size);
6683 else
6684 cbBuf = 0;
6685 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
6686 needed += size;
6687 break;
6689 case 2:
6690 size = sizeof(JOB_INFO_2W);
6691 if(cbBuf >= size)
6693 cbBuf -= size;
6694 ptr += size;
6695 memset(pJob, 0, size);
6697 else
6698 cbBuf = 0;
6699 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
6700 needed += size;
6701 break;
6703 case 3:
6704 size = sizeof(JOB_INFO_3);
6705 if(cbBuf >= size)
6707 cbBuf -= size;
6708 memset(pJob, 0, size);
6709 ret = TRUE;
6711 else
6712 cbBuf = 0;
6713 needed = size;
6714 break;
6716 default:
6717 SetLastError(ERROR_INVALID_LEVEL);
6718 goto end;
6720 if(pcbNeeded)
6721 *pcbNeeded = needed;
6722 end:
6723 LeaveCriticalSection(&printer_handles_cs);
6724 return ret;
6727 /*****************************************************************************
6728 * GetJobA [WINSPOOL.@]
6731 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6732 DWORD cbBuf, LPDWORD pcbNeeded)
6734 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
6737 /*****************************************************************************
6738 * GetJobW [WINSPOOL.@]
6741 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6742 DWORD cbBuf, LPDWORD pcbNeeded)
6744 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
6747 /*****************************************************************************
6748 * schedule_lpr
6750 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
6752 char *unixname, *queue, *cmd;
6753 char fmt[] = "lpr -P%s %s";
6754 DWORD len;
6756 if(!(unixname = wine_get_unix_file_name(filename)))
6757 return FALSE;
6759 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
6760 queue = HeapAlloc(GetProcessHeap(), 0, len);
6761 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
6763 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
6764 sprintf(cmd, fmt, queue, unixname);
6766 TRACE("printing with: %s\n", cmd);
6767 system(cmd);
6769 HeapFree(GetProcessHeap(), 0, cmd);
6770 HeapFree(GetProcessHeap(), 0, queue);
6771 HeapFree(GetProcessHeap(), 0, unixname);
6772 return TRUE;
6775 /*****************************************************************************
6776 * schedule_cups
6778 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
6780 #if HAVE_CUPS_CUPS_H
6781 if(pcupsPrintFile)
6783 char *unixname, *queue, *doc_titleA;
6784 DWORD len;
6785 BOOL ret;
6787 if(!(unixname = wine_get_unix_file_name(filename)))
6788 return FALSE;
6790 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
6791 queue = HeapAlloc(GetProcessHeap(), 0, len);
6792 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
6794 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
6795 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
6796 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
6798 TRACE("printing via cups\n");
6799 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
6800 HeapFree(GetProcessHeap(), 0, doc_titleA);
6801 HeapFree(GetProcessHeap(), 0, queue);
6802 HeapFree(GetProcessHeap(), 0, unixname);
6803 return ret;
6805 else
6806 #endif
6808 return schedule_lpr(printer_name, filename);
6812 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
6814 LPWSTR filename;
6816 switch(msg)
6818 case WM_INITDIALOG:
6819 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
6820 return TRUE;
6822 case WM_COMMAND:
6823 if(HIWORD(wparam) == BN_CLICKED)
6825 if(LOWORD(wparam) == IDOK)
6827 HANDLE hf;
6828 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
6829 LPWSTR *output;
6831 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
6832 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
6834 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
6836 WCHAR caption[200], message[200];
6837 int mb_ret;
6839 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
6840 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
6841 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
6842 if(mb_ret == IDCANCEL)
6844 HeapFree(GetProcessHeap(), 0, filename);
6845 return TRUE;
6848 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
6849 if(hf == INVALID_HANDLE_VALUE)
6851 WCHAR caption[200], message[200];
6853 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
6854 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
6855 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
6856 HeapFree(GetProcessHeap(), 0, filename);
6857 return TRUE;
6859 CloseHandle(hf);
6860 DeleteFileW(filename);
6861 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
6862 *output = filename;
6863 EndDialog(hwnd, IDOK);
6864 return TRUE;
6866 if(LOWORD(wparam) == IDCANCEL)
6868 EndDialog(hwnd, IDCANCEL);
6869 return TRUE;
6872 return FALSE;
6874 return FALSE;
6877 /*****************************************************************************
6878 * get_filename
6880 static BOOL get_filename(LPWSTR *filename)
6882 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
6883 file_dlg_proc, (LPARAM)filename) == IDOK;
6886 /*****************************************************************************
6887 * schedule_file
6889 static BOOL schedule_file(LPCWSTR filename)
6891 LPWSTR output = NULL;
6893 if(get_filename(&output))
6895 TRACE("copy to %s\n", debugstr_w(output));
6896 CopyFileW(filename, output, FALSE);
6897 HeapFree(GetProcessHeap(), 0, output);
6898 return TRUE;
6900 return FALSE;
6903 /*****************************************************************************
6904 * schedule_pipe
6906 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
6908 #ifdef HAVE_FORK
6909 char *unixname, *cmdA;
6910 DWORD len;
6911 int fds[2] = {-1, -1}, file_fd = -1, no_read;
6912 BOOL ret = FALSE;
6913 char buf[1024];
6915 if(!(unixname = wine_get_unix_file_name(filename)))
6916 return FALSE;
6918 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
6919 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
6920 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
6922 TRACE("printing with: %s\n", cmdA);
6924 if((file_fd = open(unixname, O_RDONLY)) == -1)
6925 goto end;
6927 if (pipe(fds))
6929 ERR("pipe() failed!\n");
6930 goto end;
6933 if (fork() == 0)
6935 close(0);
6936 dup2(fds[0], 0);
6937 close(fds[1]);
6939 /* reset signals that we previously set to SIG_IGN */
6940 signal(SIGPIPE, SIG_DFL);
6941 signal(SIGCHLD, SIG_DFL);
6943 system(cmdA);
6944 exit(0);
6947 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
6948 write(fds[1], buf, no_read);
6950 ret = TRUE;
6952 end:
6953 if(file_fd != -1) close(file_fd);
6954 if(fds[0] != -1) close(fds[0]);
6955 if(fds[1] != -1) close(fds[1]);
6957 HeapFree(GetProcessHeap(), 0, cmdA);
6958 HeapFree(GetProcessHeap(), 0, unixname);
6959 return ret;
6960 #else
6961 return FALSE;
6962 #endif
6965 /*****************************************************************************
6966 * schedule_unixfile
6968 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
6970 int in_fd, out_fd, no_read;
6971 char buf[1024];
6972 BOOL ret = FALSE;
6973 char *unixname, *outputA;
6974 DWORD len;
6976 if(!(unixname = wine_get_unix_file_name(filename)))
6977 return FALSE;
6979 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
6980 outputA = HeapAlloc(GetProcessHeap(), 0, len);
6981 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
6983 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
6984 in_fd = open(unixname, O_RDONLY);
6985 if(out_fd == -1 || in_fd == -1)
6986 goto end;
6988 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
6989 write(out_fd, buf, no_read);
6991 ret = TRUE;
6992 end:
6993 if(in_fd != -1) close(in_fd);
6994 if(out_fd != -1) close(out_fd);
6995 HeapFree(GetProcessHeap(), 0, outputA);
6996 HeapFree(GetProcessHeap(), 0, unixname);
6997 return ret;
7000 /*****************************************************************************
7001 * ScheduleJob [WINSPOOL.@]
7004 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7006 opened_printer_t *printer;
7007 BOOL ret = FALSE;
7008 struct list *cursor, *cursor2;
7010 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7011 EnterCriticalSection(&printer_handles_cs);
7012 printer = get_opened_printer(hPrinter);
7013 if(!printer)
7014 goto end;
7016 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7018 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7019 HANDLE hf;
7021 if(job->job_id != dwJobID) continue;
7023 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7024 if(hf != INVALID_HANDLE_VALUE)
7026 PRINTER_INFO_5W *pi5;
7027 DWORD needed;
7028 HKEY hkey;
7029 WCHAR output[1024];
7030 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7031 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7033 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7034 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7035 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7036 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7037 debugstr_w(pi5->pPortName));
7039 output[0] = 0;
7041 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7042 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7044 DWORD type, count = sizeof(output);
7045 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7046 RegCloseKey(hkey);
7048 if(output[0] == '|')
7050 schedule_pipe(output + 1, job->filename);
7052 else if(output[0])
7054 schedule_unixfile(output, job->filename);
7056 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7058 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7060 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7062 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7064 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7066 schedule_file(job->filename);
7068 else
7070 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7072 HeapFree(GetProcessHeap(), 0, pi5);
7073 CloseHandle(hf);
7074 DeleteFileW(job->filename);
7076 list_remove(cursor);
7077 HeapFree(GetProcessHeap(), 0, job->document_title);
7078 HeapFree(GetProcessHeap(), 0, job->filename);
7079 HeapFree(GetProcessHeap(), 0, job);
7080 ret = TRUE;
7081 break;
7083 end:
7084 LeaveCriticalSection(&printer_handles_cs);
7085 return ret;
7088 /*****************************************************************************
7089 * StartDocDlgA [WINSPOOL.@]
7091 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7093 UNICODE_STRING usBuffer;
7094 DOCINFOW docW;
7095 LPWSTR retW;
7096 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7097 LPSTR ret = NULL;
7099 docW.cbSize = sizeof(docW);
7100 if (doc->lpszDocName)
7102 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7103 if (!(docW.lpszDocName = docnameW)) return NULL;
7105 if (doc->lpszOutput)
7107 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7108 if (!(docW.lpszOutput = outputW)) return NULL;
7110 if (doc->lpszDatatype)
7112 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7113 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7115 docW.fwType = doc->fwType;
7117 retW = StartDocDlgW(hPrinter, &docW);
7119 if(retW)
7121 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7122 ret = HeapAlloc(GetProcessHeap(), 0, len);
7123 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7124 HeapFree(GetProcessHeap(), 0, retW);
7127 HeapFree(GetProcessHeap(), 0, datatypeW);
7128 HeapFree(GetProcessHeap(), 0, outputW);
7129 HeapFree(GetProcessHeap(), 0, docnameW);
7131 return ret;
7134 /*****************************************************************************
7135 * StartDocDlgW [WINSPOOL.@]
7137 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7138 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7139 * port is "FILE:". Also returns the full path if passed a relative path.
7141 * The caller should free the returned string from the process heap.
7143 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7145 LPWSTR ret = NULL;
7146 DWORD len, attr;
7148 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7150 PRINTER_INFO_5W *pi5;
7151 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7152 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7153 return NULL;
7154 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7155 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7156 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7158 HeapFree(GetProcessHeap(), 0, pi5);
7159 return NULL;
7161 HeapFree(GetProcessHeap(), 0, pi5);
7164 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7166 LPWSTR name;
7167 get_filename(&name);
7168 if(name)
7170 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7172 HeapFree(GetProcessHeap(), 0, name);
7173 return NULL;
7175 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7176 GetFullPathNameW(name, len, ret, NULL);
7177 HeapFree(GetProcessHeap(), 0, name);
7179 return ret;
7182 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7183 return NULL;
7185 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7186 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7188 attr = GetFileAttributesW(ret);
7189 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7191 HeapFree(GetProcessHeap(), 0, ret);
7192 ret = NULL;
7194 return ret;