winspool: Don't print NULL pointers in traces.
[wine/multimedia.git] / dlls / winspool.drv / info.c
blobabc33974447a2f7075bdb97e0e8a6074aaab3e8e
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-2008 Detlef Riekenberg
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "config.h"
27 #include "wine/port.h"
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <stddef.h>
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif
38 #include <signal.h>
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
41 #endif
43 #define NONAMELESSUNION
44 #define NONAMELESSSTRUCT
45 #include "wine/library.h"
46 #include "windef.h"
47 #include "winbase.h"
48 #include "winuser.h"
49 #include "winerror.h"
50 #include "winreg.h"
51 #include "wingdi.h"
52 #include "winspool.h"
53 #include "winternl.h"
54 #include "wine/windef16.h"
55 #include "wine/unicode.h"
56 #include "wine/debug.h"
57 #include "wine/list.h"
58 #include "winnls.h"
60 #include "ddk/winsplp.h"
61 #include "wspool.h"
63 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
65 /* ############################### */
67 static CRITICAL_SECTION monitor_handles_cs;
68 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
70 0, 0, &monitor_handles_cs,
71 { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
72 0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
74 static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
77 static CRITICAL_SECTION printer_handles_cs;
78 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
80 0, 0, &printer_handles_cs,
81 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
82 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
84 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
86 /* ############################### */
88 typedef struct {
89 struct list entry;
90 LPWSTR name;
91 LPWSTR dllname;
92 PMONITORUI monitorUI;
93 LPMONITOR monitor;
94 HMODULE hdll;
95 DWORD refcount;
96 DWORD dwMonitorSize;
97 } monitor_t;
99 typedef struct {
100 DWORD job_id;
101 HANDLE hf;
102 } started_doc_t;
104 typedef struct {
105 struct list jobs;
106 LONG ref;
107 } jobqueue_t;
109 typedef struct {
110 LPWSTR name;
111 LPWSTR printername;
112 monitor_t *pm;
113 HANDLE hXcv;
114 jobqueue_t *queue;
115 started_doc_t *doc;
116 } opened_printer_t;
118 typedef struct {
119 struct list entry;
120 DWORD job_id;
121 WCHAR *filename;
122 WCHAR *document_title;
123 } job_t;
126 typedef struct {
127 LPCWSTR envname;
128 LPCWSTR subdir;
129 DWORD driverversion;
130 LPCWSTR versionregpath;
131 LPCWSTR versionsubdir;
132 } printenv_t;
134 /* ############################### */
136 static struct list monitor_handles = LIST_INIT( monitor_handles );
137 static monitor_t * pm_localport;
139 static opened_printer_t **printer_handles;
140 static UINT nb_printer_handles;
141 static LONG next_job_id = 1;
143 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
144 WORD fwCapability, LPSTR lpszOutput,
145 LPDEVMODEA lpdm );
146 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
147 LPSTR lpszDevice, LPSTR lpszPort,
148 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
149 DWORD fwMode );
151 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
152 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
153 'c','o','n','t','r','o','l','\\',
154 'P','r','i','n','t','\\',
155 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
156 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
158 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
159 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
160 'C','o','n','t','r','o','l','\\',
161 'P','r','i','n','t','\\',
162 'M','o','n','i','t','o','r','s','\\',0};
164 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
165 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
166 'C','o','n','t','r','o','l','\\',
167 'P','r','i','n','t','\\',
168 'P','r','i','n','t','e','r','s',0};
170 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
172 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
173 'M','i','c','r','o','s','o','f','t','\\',
174 'W','i','n','d','o','w','s',' ','N','T','\\',
175 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
176 'W','i','n','d','o','w','s',0};
178 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
179 'M','i','c','r','o','s','o','f','t','\\',
180 'W','i','n','d','o','w','s',' ','N','T','\\',
181 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
182 'D','e','v','i','c','e','s',0};
184 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
185 'M','i','c','r','o','s','o','f','t','\\',
186 'W','i','n','d','o','w','s',' ','N','T','\\',
187 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
188 'P','o','r','t','s',0};
190 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
191 'M','i','c','r','o','s','o','f','t','\\',
192 'W','i','n','d','o','w','s',' ','N','T','\\',
193 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
194 'P','r','i','n','t','e','r','P','o','r','t','s',0};
196 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
197 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
198 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
199 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
200 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
201 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
202 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
203 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
204 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
206 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
207 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
209 static const WCHAR backslashW[] = {'\\',0};
210 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
211 'i','o','n',' ','F','i','l','e',0};
212 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
213 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
214 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
215 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
216 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
217 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
218 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
219 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
220 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
221 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
222 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
223 static const WCHAR MonitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
224 static const WCHAR NameW[] = {'N','a','m','e',0};
225 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
226 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
227 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
228 static const WCHAR PortW[] = {'P','o','r','t',0};
229 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
230 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
231 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
232 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
233 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
234 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
235 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
236 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
237 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
238 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
239 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
240 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
241 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
242 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
243 static const WCHAR emptyStringW[] = {0};
244 static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
245 static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
247 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
249 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
250 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
251 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
253 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
254 'D','o','c','u','m','e','n','t',0};
256 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
257 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
258 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
259 0, sizeof(DRIVER_INFO_8W)};
262 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
263 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
264 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
265 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
266 sizeof(PRINTER_INFO_9W)};
268 /******************************************************************
269 * validate the user-supplied printing-environment [internal]
271 * PARAMS
272 * env [I] PTR to Environment-String or NULL
274 * RETURNS
275 * Failure: NULL
276 * Success: PTR to printenv_t
278 * NOTES
279 * An empty string is handled the same way as NULL.
280 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
284 static const printenv_t * validate_envW(LPCWSTR env)
286 static const printenv_t env_x86 = {envname_x86W, subdir_x86W,
287 3, Version3_RegPathW, Version3_SubdirW};
288 static const printenv_t env_win40 = {envname_win40W, subdir_win40W,
289 0, Version0_RegPathW, Version0_SubdirW};
291 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
293 const printenv_t *result = NULL;
294 unsigned int i;
296 TRACE("testing %s\n", debugstr_w(env));
297 if (env && env[0])
299 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
301 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
303 result = all_printenv[i];
304 break;
308 if (result == NULL) {
309 FIXME("unsupported Environment: %s\n", debugstr_w(env));
310 SetLastError(ERROR_INVALID_ENVIRONMENT);
312 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
314 else
316 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
318 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
320 return result;
324 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
325 if passed a NULL string. This returns NULLs to the result.
327 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
329 if ( (src) )
331 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
332 return usBufferPtr->Buffer;
334 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
335 return NULL;
338 static LPWSTR strdupW(LPCWSTR p)
340 LPWSTR ret;
341 DWORD len;
343 if(!p) return NULL;
344 len = (strlenW(p) + 1) * sizeof(WCHAR);
345 ret = HeapAlloc(GetProcessHeap(), 0, len);
346 memcpy(ret, p, len);
347 return ret;
350 static LPSTR strdupWtoA( LPCWSTR str )
352 LPSTR ret;
353 INT len;
355 if (!str) return NULL;
356 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
357 ret = HeapAlloc( GetProcessHeap(), 0, len );
358 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
359 return ret;
362 /******************************************************************
363 * Return the number of bytes for an multi_sz string.
364 * The result includes all \0s
365 * (specifically the extra \0, that is needed as multi_sz terminator).
367 #if 0
368 static int multi_sz_lenW(const WCHAR *str)
370 const WCHAR *ptr = str;
371 if(!str) return 0;
374 ptr += lstrlenW(ptr) + 1;
375 } while(*ptr);
377 return (ptr - str + 1) * sizeof(WCHAR);
379 #endif
380 /* ################################ */
382 static int multi_sz_lenA(const char *str)
384 const char *ptr = str;
385 if(!str) return 0;
388 ptr += lstrlenA(ptr) + 1;
389 } while(*ptr);
391 return ptr - str + 1;
394 static void
395 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
396 char qbuf[200];
398 /* If forcing, or no profile string entry for device yet, set the entry
400 * The always change entry if not WINEPS yet is discussable.
402 if (force ||
403 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
404 !strcmp(qbuf,"*") ||
405 !strstr(qbuf,"WINEPS.DRV")
407 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
408 HKEY hkey;
410 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
411 WriteProfileStringA("windows","device",buf);
412 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
413 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
414 RegCloseKey(hkey);
416 HeapFree(GetProcessHeap(),0,buf);
420 static BOOL add_printer_driver(const char *name)
422 DRIVER_INFO_3A di3a;
424 static char driver_9x[] = "wineps16.drv",
425 driver_nt[] = "wineps.drv",
426 env_9x[] = "Windows 4.0",
427 env_nt[] = "Windows NT x86",
428 data_file[] = "generic.ppd",
429 default_data_type[] = "RAW";
431 ZeroMemory(&di3a, sizeof(DRIVER_INFO_3A));
432 di3a.cVersion = 3;
433 di3a.pName = (char *)name;
434 di3a.pEnvironment = env_nt;
435 di3a.pDriverPath = driver_nt;
436 di3a.pDataFile = data_file;
437 di3a.pConfigFile = driver_nt;
438 di3a.pDefaultDataType = default_data_type;
440 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
441 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
443 di3a.cVersion = 0;
444 di3a.pEnvironment = env_9x;
445 di3a.pDriverPath = driver_9x;
446 di3a.pConfigFile = driver_9x;
447 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
448 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
450 return TRUE;
453 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a.pDriverPath),
454 debugstr_a(di3a.pEnvironment), GetLastError());
455 return FALSE;
458 #ifdef SONAME_LIBCUPS
459 static typeof(cupsGetDests) *pcupsGetDests;
460 static typeof(cupsGetPPD) *pcupsGetPPD;
461 static typeof(cupsPrintFile) *pcupsPrintFile;
462 static void *cupshandle;
464 static BOOL CUPS_LoadPrinters(void)
466 int i, nrofdests;
467 BOOL hadprinter = FALSE, haddefault = FALSE;
468 cups_dest_t *dests;
469 PRINTER_INFO_2A pinfo2a;
470 char *port,*devline;
471 HKEY hkeyPrinter, hkeyPrinters, hkey;
472 char loaderror[256];
474 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
475 if (!cupshandle) {
476 TRACE("%s\n", loaderror);
477 return FALSE;
479 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
481 #define DYNCUPS(x) \
482 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
483 if (!p##x) return FALSE;
485 DYNCUPS(cupsGetPPD);
486 DYNCUPS(cupsGetDests);
487 DYNCUPS(cupsPrintFile);
488 #undef DYNCUPS
490 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
491 ERROR_SUCCESS) {
492 ERR("Can't create Printers key\n");
493 return FALSE;
496 nrofdests = pcupsGetDests(&dests);
497 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
498 for (i=0;i<nrofdests;i++) {
499 /* FIXME: replace "LPR:" with "CUPS:". Fix printing output first */
500 port = HeapAlloc(GetProcessHeap(), 0, strlen("LPR:") + strlen(dests[i].name)+1);
501 sprintf(port,"LPR:%s", dests[i].name);
502 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
503 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
504 sprintf(devline, "WINEPS.DRV,%s", port);
505 WriteProfileStringA("devices", dests[i].name, devline);
506 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
507 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
508 RegCloseKey(hkey);
511 lstrcatA(devline, ",15,45");
512 WriteProfileStringA("PrinterPorts", dests[i].name, devline);
513 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
514 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
515 RegCloseKey(hkey);
518 HeapFree(GetProcessHeap(), 0, devline);
520 TRACE("Printer %d: %s\n", i, dests[i].name);
521 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
522 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
523 and continue */
524 TRACE("Printer already exists\n");
525 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
526 RegCloseKey(hkeyPrinter);
527 } else {
528 static CHAR data_type[] = "RAW",
529 print_proc[] = "WinPrint",
530 comment[] = "WINEPS Printer using CUPS",
531 location[] = "<physical location of printer>",
532 params[] = "<parameters?>",
533 share_name[] = "<share name?>",
534 sep_file[] = "<sep file?>";
536 add_printer_driver(dests[i].name);
538 memset(&pinfo2a,0,sizeof(pinfo2a));
539 pinfo2a.pPrinterName = dests[i].name;
540 pinfo2a.pDatatype = data_type;
541 pinfo2a.pPrintProcessor = print_proc;
542 pinfo2a.pDriverName = dests[i].name;
543 pinfo2a.pComment = comment;
544 pinfo2a.pLocation = location;
545 pinfo2a.pPortName = port;
546 pinfo2a.pParameters = params;
547 pinfo2a.pShareName = share_name;
548 pinfo2a.pSepFile = sep_file;
550 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
551 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
552 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
555 HeapFree(GetProcessHeap(),0,port);
557 hadprinter = TRUE;
558 if (dests[i].is_default) {
559 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
560 haddefault = TRUE;
563 if (hadprinter & !haddefault)
564 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
565 RegCloseKey(hkeyPrinters);
566 return hadprinter;
568 #endif
570 static BOOL
571 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
572 PRINTER_INFO_2A pinfo2a;
573 char *e,*s,*name,*prettyname,*devname;
574 BOOL ret = FALSE, set_default = FALSE;
575 char *port = NULL, *devline,*env_default;
576 HKEY hkeyPrinter, hkeyPrinters, hkey;
578 while (isspace(*pent)) pent++;
579 s = strchr(pent,':');
580 if(s) *s='\0';
581 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
582 strcpy(name,pent);
583 if(s) {
584 *s=':';
585 pent = s;
586 } else
587 pent = "";
589 TRACE("name=%s entry=%s\n",name, pent);
591 if(ispunct(*name)) { /* a tc entry, not a real printer */
592 TRACE("skipping tc entry\n");
593 goto end;
596 if(strstr(pent,":server")) { /* server only version so skip */
597 TRACE("skipping server entry\n");
598 goto end;
601 /* Determine whether this is a postscript printer. */
603 ret = TRUE;
604 env_default = getenv("PRINTER");
605 prettyname = name;
606 /* Get longest name, usually the one at the right for later display. */
607 while((s=strchr(prettyname,'|'))) {
608 *s = '\0';
609 e = s;
610 while(isspace(*--e)) *e = '\0';
611 TRACE("\t%s\n", debugstr_a(prettyname));
612 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
613 for(prettyname = s+1; isspace(*prettyname); prettyname++)
616 e = prettyname + strlen(prettyname);
617 while(isspace(*--e)) *e = '\0';
618 TRACE("\t%s\n", debugstr_a(prettyname));
619 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
621 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
622 * if it is too long, we use it as comment below. */
623 devname = prettyname;
624 if (strlen(devname)>=CCHDEVICENAME-1)
625 devname = name;
626 if (strlen(devname)>=CCHDEVICENAME-1) {
627 ret = FALSE;
628 goto end;
631 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
632 sprintf(port,"LPR:%s",name);
634 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
635 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
636 sprintf(devline, "WINEPS.DRV,%s", port);
637 WriteProfileStringA("devices", devname, devline);
638 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
639 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
640 RegCloseKey(hkey);
643 lstrcatA(devline, ",15,45");
644 WriteProfileStringA("PrinterPorts", devname, devline);
645 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
646 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
647 RegCloseKey(hkey);
650 HeapFree(GetProcessHeap(),0,devline);
652 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
653 ERROR_SUCCESS) {
654 ERR("Can't create Printers key\n");
655 ret = FALSE;
656 goto end;
658 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
659 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
660 and continue */
661 TRACE("Printer already exists\n");
662 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
663 RegCloseKey(hkeyPrinter);
664 } else {
665 static CHAR data_type[] = "RAW",
666 print_proc[] = "WinPrint",
667 comment[] = "WINEPS Printer using LPR",
668 params[] = "<parameters?>",
669 share_name[] = "<share name?>",
670 sep_file[] = "<sep file?>";
672 add_printer_driver(devname);
674 memset(&pinfo2a,0,sizeof(pinfo2a));
675 pinfo2a.pPrinterName = devname;
676 pinfo2a.pDatatype = data_type;
677 pinfo2a.pPrintProcessor = print_proc;
678 pinfo2a.pDriverName = devname;
679 pinfo2a.pComment = comment;
680 pinfo2a.pLocation = prettyname;
681 pinfo2a.pPortName = port;
682 pinfo2a.pParameters = params;
683 pinfo2a.pShareName = share_name;
684 pinfo2a.pSepFile = sep_file;
686 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
687 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
688 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
691 RegCloseKey(hkeyPrinters);
693 if (isfirst || set_default)
694 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
696 end:
697 HeapFree(GetProcessHeap(), 0, port);
698 HeapFree(GetProcessHeap(), 0, name);
699 return ret;
702 static BOOL
703 PRINTCAP_LoadPrinters(void) {
704 BOOL hadprinter = FALSE;
705 char buf[200];
706 FILE *f;
707 char *pent = NULL;
708 BOOL had_bash = FALSE;
710 f = fopen("/etc/printcap","r");
711 if (!f)
712 return FALSE;
714 while(fgets(buf,sizeof(buf),f)) {
715 char *start, *end;
717 end=strchr(buf,'\n');
718 if (end) *end='\0';
720 start = buf;
721 while(isspace(*start)) start++;
722 if(*start == '#' || *start == '\0')
723 continue;
725 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
726 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
727 HeapFree(GetProcessHeap(),0,pent);
728 pent = NULL;
731 if (end && *--end == '\\') {
732 *end = '\0';
733 had_bash = TRUE;
734 } else
735 had_bash = FALSE;
737 if (pent) {
738 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
739 strcat(pent,start);
740 } else {
741 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
742 strcpy(pent,start);
746 if(pent) {
747 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
748 HeapFree(GetProcessHeap(),0,pent);
750 fclose(f);
751 return hadprinter;
754 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
756 if (value)
757 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
758 (lstrlenW(value) + 1) * sizeof(WCHAR));
759 else
760 return ERROR_FILE_NOT_FOUND;
763 /*****************************************************************************
764 * enumerate the local monitors (INTERNAL)
766 * returns the needed size (in bytes) for pMonitors
767 * and *lpreturned is set to number of entries returned in pMonitors
770 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
772 HKEY hroot = NULL;
773 HKEY hentry = NULL;
774 LPWSTR ptr;
775 LPMONITOR_INFO_2W mi;
776 WCHAR buffer[MAX_PATH];
777 WCHAR dllname[MAX_PATH];
778 DWORD dllsize;
779 DWORD len;
780 DWORD index = 0;
781 DWORD needed = 0;
782 DWORD numentries;
783 DWORD entrysize;
785 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
787 numentries = *lpreturned; /* this is 0, when we scan the registry */
788 len = entrysize * numentries;
789 ptr = (LPWSTR) &pMonitors[len];
791 numentries = 0;
792 len = sizeof(buffer)/sizeof(buffer[0]);
793 buffer[0] = '\0';
795 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
796 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
797 /* Scan all Monitor-Registry-Keys */
798 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
799 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
800 dllsize = sizeof(dllname);
801 dllname[0] = '\0';
803 /* The Monitor must have a Driver-DLL */
804 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
805 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
806 /* We found a valid DLL for this Monitor. */
807 TRACE("using Driver: %s\n", debugstr_w(dllname));
809 RegCloseKey(hentry);
812 /* Windows returns only Port-Monitors here, but to simplify our code,
813 we do no filtering for Language-Monitors */
814 if (dllname[0]) {
815 numentries++;
816 needed += entrysize;
817 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
818 if (level > 1) {
819 /* we install and return only monitors for "Windows NT x86" */
820 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
821 needed += dllsize;
824 /* required size is calculated. Now fill the user-buffer */
825 if (pMonitors && (cbBuf >= needed)){
826 mi = (LPMONITOR_INFO_2W) pMonitors;
827 pMonitors += entrysize;
829 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
830 mi->pName = ptr;
831 lstrcpyW(ptr, buffer); /* Name of the Monitor */
832 ptr += (len+1); /* len is lstrlenW(monitorname) */
833 if (level > 1) {
834 mi->pEnvironment = ptr;
835 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
836 ptr += (lstrlenW(envname_x86W)+1);
838 mi->pDLLName = ptr;
839 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
840 ptr += (dllsize / sizeof(WCHAR));
844 index++;
845 len = sizeof(buffer)/sizeof(buffer[0]);
846 buffer[0] = '\0';
848 RegCloseKey(hroot);
850 *lpreturned = numentries;
851 TRACE("need %d byte for %d entries\n", needed, numentries);
852 return needed;
855 /******************************************************************
856 * monitor_unload [internal]
858 * release a printmonitor and unload it from memory, when needed
861 static void monitor_unload(monitor_t * pm)
863 if (pm == NULL) return;
864 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
866 EnterCriticalSection(&monitor_handles_cs);
868 if (pm->refcount) pm->refcount--;
870 if (pm->refcount == 0) {
871 list_remove(&pm->entry);
872 FreeLibrary(pm->hdll);
873 HeapFree(GetProcessHeap(), 0, pm->name);
874 HeapFree(GetProcessHeap(), 0, pm->dllname);
875 HeapFree(GetProcessHeap(), 0, pm);
877 LeaveCriticalSection(&monitor_handles_cs);
880 /******************************************************************
881 * monitor_unloadall [internal]
883 * release all printmonitors and unload them from memory, when needed
886 static void monitor_unloadall(void)
888 monitor_t * pm;
889 monitor_t * next;
891 EnterCriticalSection(&monitor_handles_cs);
892 /* iterate through the list, with safety against removal */
893 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
895 monitor_unload(pm);
897 LeaveCriticalSection(&monitor_handles_cs);
900 /******************************************************************
901 * monitor_load [internal]
903 * load a printmonitor, get the dllname from the registry, when needed
904 * initialize the monitor and dump found function-pointers
906 * On failure, SetLastError() is called and NULL is returned
909 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
911 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
912 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
913 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
914 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
915 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
917 monitor_t * pm = NULL;
918 monitor_t * cursor;
919 LPWSTR regroot = NULL;
920 LPWSTR driver = dllname;
922 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
923 /* Is the Monitor already loaded? */
924 EnterCriticalSection(&monitor_handles_cs);
926 if (name) {
927 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
929 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
930 pm = cursor;
931 break;
936 if (pm == NULL) {
937 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
938 if (pm == NULL) goto cleanup;
939 list_add_tail(&monitor_handles, &pm->entry);
941 pm->refcount++;
943 if (pm->name == NULL) {
944 /* Load the monitor */
945 LPMONITOREX pmonitorEx;
946 DWORD len;
948 if (name) {
949 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
950 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
953 if (regroot) {
954 lstrcpyW(regroot, MonitorsW);
955 lstrcatW(regroot, name);
956 /* Get the Driver from the Registry */
957 if (driver == NULL) {
958 HKEY hroot;
959 DWORD namesize;
960 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
961 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
962 &namesize) == ERROR_SUCCESS) {
963 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
964 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
966 RegCloseKey(hroot);
971 pm->name = strdupW(name);
972 pm->dllname = strdupW(driver);
974 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
975 monitor_unload(pm);
976 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
977 pm = NULL;
978 goto cleanup;
981 pm->hdll = LoadLibraryW(driver);
982 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
984 if (pm->hdll == NULL) {
985 monitor_unload(pm);
986 SetLastError(ERROR_MOD_NOT_FOUND);
987 pm = NULL;
988 goto cleanup;
991 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
992 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
993 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
994 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
995 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
998 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
999 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
1000 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
1001 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
1002 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
1004 if (pInitializePrintMonitorUI != NULL) {
1005 pm->monitorUI = pInitializePrintMonitorUI();
1006 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
1007 if (pm->monitorUI) {
1008 TRACE( "0x%08x: dwMonitorSize (%d)\n",
1009 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
1014 if (pInitializePrintMonitor && regroot) {
1015 pmonitorEx = pInitializePrintMonitor(regroot);
1016 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
1017 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
1019 if (pmonitorEx) {
1020 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
1021 pm->monitor = &(pmonitorEx->Monitor);
1025 if (pm->monitor) {
1026 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
1030 if (!pm->monitor && regroot) {
1031 if (pInitializePrintMonitor2 != NULL) {
1032 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
1034 if (pInitializeMonitorEx != NULL) {
1035 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
1037 if (pInitializeMonitor != NULL) {
1038 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
1041 if (!pm->monitor && !pm->monitorUI) {
1042 monitor_unload(pm);
1043 SetLastError(ERROR_PROC_NOT_FOUND);
1044 pm = NULL;
1047 cleanup:
1048 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
1049 pm->refcount++;
1050 pm_localport = pm;
1052 LeaveCriticalSection(&monitor_handles_cs);
1053 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
1054 HeapFree(GetProcessHeap(), 0, regroot);
1055 TRACE("=> %p\n", pm);
1056 return pm;
1059 /******************************************************************
1060 * monitor_loadall [internal]
1062 * Load all registered monitors
1065 static DWORD monitor_loadall(void)
1067 monitor_t * pm;
1068 DWORD registered = 0;
1069 DWORD loaded = 0;
1070 HKEY hmonitors;
1071 WCHAR buffer[MAX_PATH];
1072 DWORD id = 0;
1074 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hmonitors) == ERROR_SUCCESS) {
1075 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
1076 NULL, NULL, NULL, NULL, NULL);
1078 TRACE("%d monitors registered\n", registered);
1080 EnterCriticalSection(&monitor_handles_cs);
1081 while (id < registered) {
1082 buffer[0] = '\0';
1083 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
1084 pm = monitor_load(buffer, NULL);
1085 if (pm) loaded++;
1086 id++;
1088 LeaveCriticalSection(&monitor_handles_cs);
1089 RegCloseKey(hmonitors);
1091 TRACE("%d monitors loaded\n", loaded);
1092 return loaded;
1095 /******************************************************************
1096 * monitor_loadui [internal]
1098 * load the userinterface-dll for a given portmonitor
1100 * On failure, NULL is returned
1103 static monitor_t * monitor_loadui(monitor_t * pm)
1105 monitor_t * pui = NULL;
1106 LPWSTR buffer[MAX_PATH];
1107 HANDLE hXcv;
1108 DWORD len;
1109 DWORD res;
1111 if (pm == NULL) return NULL;
1112 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
1114 /* Try the Portmonitor first; works for many monitors */
1115 if (pm->monitorUI) {
1116 EnterCriticalSection(&monitor_handles_cs);
1117 pm->refcount++;
1118 LeaveCriticalSection(&monitor_handles_cs);
1119 return pm;
1122 /* query the userinterface-dllname from the Portmonitor */
1123 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
1124 /* building (",XcvMonitor %s",pm->name) not needed yet */
1125 res = pm->monitor->pfnXcvOpenPort(emptyStringW, SERVER_ACCESS_ADMINISTER, &hXcv);
1126 TRACE("got %u with %p\n", res, hXcv);
1127 if (res) {
1128 res = pm->monitor->pfnXcvDataPort(hXcv, MonitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
1129 TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
1130 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
1131 pm->monitor->pfnXcvClosePort(hXcv);
1134 return pui;
1138 /******************************************************************
1139 * monitor_load_by_port [internal]
1141 * load a printmonitor for a given port
1143 * On failure, NULL is returned
1146 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1148 HKEY hroot;
1149 HKEY hport;
1150 LPWSTR buffer;
1151 monitor_t * pm = NULL;
1152 DWORD registered = 0;
1153 DWORD id = 0;
1154 DWORD len;
1156 TRACE("(%s)\n", debugstr_w(portname));
1158 /* Try the Local Monitor first */
1159 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1160 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1161 /* found the portname */
1162 RegCloseKey(hroot);
1163 return monitor_load(LocalPortW, NULL);
1165 RegCloseKey(hroot);
1168 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1169 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1170 if (buffer == NULL) return NULL;
1172 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1173 EnterCriticalSection(&monitor_handles_cs);
1174 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1176 while ((pm == NULL) && (id < registered)) {
1177 buffer[0] = '\0';
1178 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1179 TRACE("testing %s\n", debugstr_w(buffer));
1180 len = lstrlenW(buffer);
1181 lstrcatW(buffer, bs_Ports_bsW);
1182 lstrcatW(buffer, portname);
1183 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1184 RegCloseKey(hport);
1185 buffer[len] = '\0'; /* use only the Monitor-Name */
1186 pm = monitor_load(buffer, NULL);
1188 id++;
1190 LeaveCriticalSection(&monitor_handles_cs);
1191 RegCloseKey(hroot);
1193 HeapFree(GetProcessHeap(), 0, buffer);
1194 return pm;
1197 /******************************************************************
1198 * enumerate the local Ports from all loaded monitors (internal)
1200 * returns the needed size (in bytes) for pPorts
1201 * and *lpreturned is set to number of entries returned in pPorts
1204 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
1206 monitor_t * pm;
1207 LPWSTR ptr;
1208 LPPORT_INFO_2W cache;
1209 LPPORT_INFO_2W out;
1210 LPBYTE pi_buffer = NULL;
1211 DWORD pi_allocated = 0;
1212 DWORD pi_needed;
1213 DWORD pi_index;
1214 DWORD pi_returned;
1215 DWORD res;
1216 DWORD outindex = 0;
1217 DWORD needed;
1218 DWORD numentries;
1219 DWORD entrysize;
1222 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
1223 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
1225 numentries = *lpreturned; /* this is 0, when we scan the registry */
1226 needed = entrysize * numentries;
1227 ptr = (LPWSTR) &pPorts[needed];
1229 numentries = 0;
1230 needed = 0;
1232 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1234 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
1235 pi_needed = 0;
1236 pi_returned = 0;
1237 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1238 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
1239 /* Do not use HeapReAlloc (we do not need the old data in the buffer) */
1240 HeapFree(GetProcessHeap(), 0, pi_buffer);
1241 pi_buffer = HeapAlloc(GetProcessHeap(), 0, pi_needed);
1242 pi_allocated = (pi_buffer) ? pi_needed : 0;
1243 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1245 TRACE( "(%s) got %d with %d (need %d byte for %d entries)\n",
1246 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
1248 numentries += pi_returned;
1249 needed += pi_needed;
1251 /* fill the output-buffer (pPorts), if we have one */
1252 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
1253 pi_index = 0;
1254 while (pi_returned > pi_index) {
1255 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
1256 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
1257 out->pPortName = ptr;
1258 lstrcpyW(ptr, cache->pPortName);
1259 ptr += (lstrlenW(ptr)+1);
1260 if (level > 1) {
1261 out->pMonitorName = ptr;
1262 lstrcpyW(ptr, cache->pMonitorName);
1263 ptr += (lstrlenW(ptr)+1);
1265 out->pDescription = ptr;
1266 lstrcpyW(ptr, cache->pDescription);
1267 ptr += (lstrlenW(ptr)+1);
1268 out->fPortType = cache->fPortType;
1269 out->Reserved = cache->Reserved;
1271 pi_index++;
1272 outindex++;
1277 /* the temporary portinfo-buffer is no longer needed */
1278 HeapFree(GetProcessHeap(), 0, pi_buffer);
1280 *lpreturned = numentries;
1281 TRACE("need %d byte for %d entries\n", needed, numentries);
1282 return needed;
1285 /******************************************************************
1286 * get_servername_from_name (internal)
1288 * for an external server, a copy of the serverpart from the full name is returned
1291 static LPWSTR get_servername_from_name(LPCWSTR name)
1293 LPWSTR server;
1294 LPWSTR ptr;
1295 WCHAR buffer[MAX_PATH];
1296 DWORD len;
1298 if (name == NULL) return NULL;
1299 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1301 server = strdupW(&name[2]); /* skip over both backslash */
1302 if (server == NULL) return NULL;
1304 /* strip '\' and the printername */
1305 ptr = strchrW(server, '\\');
1306 if (ptr) ptr[0] = '\0';
1308 TRACE("found %s\n", debugstr_w(server));
1310 len = sizeof(buffer)/sizeof(buffer[0]);
1311 if (GetComputerNameW(buffer, &len)) {
1312 if (lstrcmpW(buffer, server) == 0) {
1313 /* The requested Servername is our computername */
1314 HeapFree(GetProcessHeap(), 0, server);
1315 return NULL;
1318 return server;
1321 /******************************************************************
1322 * get_basename_from_name (internal)
1324 * skip over the serverpart from the full name
1327 static LPCWSTR get_basename_from_name(LPCWSTR name)
1329 if (name == NULL) return NULL;
1330 if ((name[0] == '\\') && (name[1] == '\\')) {
1331 /* skip over the servername and search for the following '\' */
1332 name = strchrW(&name[2], '\\');
1333 if ((name) && (name[1])) {
1334 /* found a separator ('\') followed by a name:
1335 skip over the separator and return the rest */
1336 name++;
1338 else
1340 /* no basename present (we found only a servername) */
1341 return NULL;
1344 return name;
1347 /******************************************************************
1348 * get_opened_printer_entry
1349 * Get the first place empty in the opened printer table
1351 * ToDo:
1352 * - pDefault is ignored
1354 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1356 UINT_PTR handle = nb_printer_handles, i;
1357 jobqueue_t *queue = NULL;
1358 opened_printer_t *printer = NULL;
1359 LPWSTR servername;
1360 LPCWSTR printername;
1361 HKEY hkeyPrinters;
1362 HKEY hkeyPrinter;
1363 DWORD len;
1365 servername = get_servername_from_name(name);
1366 if (servername) {
1367 FIXME("server %s not supported\n", debugstr_w(servername));
1368 HeapFree(GetProcessHeap(), 0, servername);
1369 SetLastError(ERROR_INVALID_PRINTER_NAME);
1370 return NULL;
1373 printername = get_basename_from_name(name);
1374 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1376 /* an empty printername is invalid */
1377 if (printername && (!printername[0])) {
1378 SetLastError(ERROR_INVALID_PARAMETER);
1379 return NULL;
1382 EnterCriticalSection(&printer_handles_cs);
1384 for (i = 0; i < nb_printer_handles; i++)
1386 if (!printer_handles[i])
1388 if(handle == nb_printer_handles)
1389 handle = i;
1391 else
1393 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1394 queue = printer_handles[i]->queue;
1398 if (handle >= nb_printer_handles)
1400 opened_printer_t **new_array;
1401 if (printer_handles)
1402 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1403 (nb_printer_handles + 16) * sizeof(*new_array) );
1404 else
1405 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1406 (nb_printer_handles + 16) * sizeof(*new_array) );
1408 if (!new_array)
1410 handle = 0;
1411 goto end;
1413 printer_handles = new_array;
1414 nb_printer_handles += 16;
1417 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1419 handle = 0;
1420 goto end;
1424 /* clone the base name. This is NULL for the printserver */
1425 printer->printername = strdupW(printername);
1427 /* clone the full name */
1428 printer->name = strdupW(name);
1429 if (name && (!printer->name)) {
1430 handle = 0;
1431 goto end;
1434 if (printername) {
1435 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1436 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1437 /* OpenPrinter(",XcvMonitor " detected */
1438 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1439 printer->pm = monitor_load(&printername[len], NULL);
1440 if (printer->pm == NULL) {
1441 SetLastError(ERROR_UNKNOWN_PORT);
1442 handle = 0;
1443 goto end;
1446 else
1448 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1449 if (strncmpW( printername, XcvPortW, len) == 0) {
1450 /* OpenPrinter(",XcvPort " detected */
1451 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1452 printer->pm = monitor_load_by_port(&printername[len]);
1453 if (printer->pm == NULL) {
1454 SetLastError(ERROR_UNKNOWN_PORT);
1455 handle = 0;
1456 goto end;
1461 if (printer->pm) {
1462 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1463 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1464 pDefault ? pDefault->DesiredAccess : 0,
1465 &printer->hXcv);
1467 if (printer->hXcv == NULL) {
1468 SetLastError(ERROR_INVALID_PARAMETER);
1469 handle = 0;
1470 goto end;
1473 else
1475 /* Does the Printer exist? */
1476 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1477 ERR("Can't create Printers key\n");
1478 handle = 0;
1479 goto end;
1481 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1482 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1483 RegCloseKey(hkeyPrinters);
1484 SetLastError(ERROR_INVALID_PRINTER_NAME);
1485 handle = 0;
1486 goto end;
1488 RegCloseKey(hkeyPrinter);
1489 RegCloseKey(hkeyPrinters);
1492 else
1494 TRACE("using the local printserver\n");
1497 if(queue)
1498 printer->queue = queue;
1499 else
1501 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1502 if (!printer->queue) {
1503 handle = 0;
1504 goto end;
1506 list_init(&printer->queue->jobs);
1507 printer->queue->ref = 0;
1509 InterlockedIncrement(&printer->queue->ref);
1511 printer_handles[handle] = printer;
1512 handle++;
1513 end:
1514 LeaveCriticalSection(&printer_handles_cs);
1515 if (!handle && printer) {
1516 /* Something failed: Free all resources */
1517 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1518 monitor_unload(printer->pm);
1519 HeapFree(GetProcessHeap(), 0, printer->printername);
1520 HeapFree(GetProcessHeap(), 0, printer->name);
1521 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1522 HeapFree(GetProcessHeap(), 0, printer);
1525 return (HANDLE)handle;
1528 /******************************************************************
1529 * get_opened_printer
1530 * Get the pointer to the opened printer referred by the handle
1532 static opened_printer_t *get_opened_printer(HANDLE hprn)
1534 UINT_PTR idx = (UINT_PTR)hprn;
1535 opened_printer_t *ret = NULL;
1537 EnterCriticalSection(&printer_handles_cs);
1539 if ((idx > 0) && (idx <= nb_printer_handles)) {
1540 ret = printer_handles[idx - 1];
1542 LeaveCriticalSection(&printer_handles_cs);
1543 return ret;
1546 /******************************************************************
1547 * get_opened_printer_name
1548 * Get the pointer to the opened printer name referred by the handle
1550 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1552 opened_printer_t *printer = get_opened_printer(hprn);
1553 if(!printer) return NULL;
1554 return printer->name;
1557 /******************************************************************
1558 * WINSPOOL_GetOpenedPrinterRegKey
1561 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1563 LPCWSTR name = get_opened_printer_name(hPrinter);
1564 DWORD ret;
1565 HKEY hkeyPrinters;
1567 if(!name) return ERROR_INVALID_HANDLE;
1569 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1570 ERROR_SUCCESS)
1571 return ret;
1573 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1575 ERR("Can't find opened printer %s in registry\n",
1576 debugstr_w(name));
1577 RegCloseKey(hkeyPrinters);
1578 return ERROR_INVALID_PRINTER_NAME; /* ? */
1580 RegCloseKey(hkeyPrinters);
1581 return ERROR_SUCCESS;
1584 void WINSPOOL_LoadSystemPrinters(void)
1586 HKEY hkey, hkeyPrinters;
1587 HANDLE hprn;
1588 DWORD needed, num, i;
1589 WCHAR PrinterName[256];
1590 BOOL done = FALSE;
1592 /* This ensures that all printer entries have a valid Name value. If causes
1593 problems later if they don't. If one is found to be missed we create one
1594 and set it equal to the name of the key */
1595 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1596 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1597 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1598 for(i = 0; i < num; i++) {
1599 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1600 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1601 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1602 set_reg_szW(hkey, NameW, PrinterName);
1604 RegCloseKey(hkey);
1609 RegCloseKey(hkeyPrinters);
1612 /* We want to avoid calling AddPrinter on printers as much as
1613 possible, because on cups printers this will (eventually) lead
1614 to a call to cupsGetPPD which takes forever, even with non-cups
1615 printers AddPrinter takes a while. So we'll tag all printers that
1616 were automatically added last time around, if they still exist
1617 we'll leave them be otherwise we'll delete them. */
1618 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1619 if(needed) {
1620 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1621 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1622 for(i = 0; i < num; i++) {
1623 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1624 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1625 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1626 DWORD dw = 1;
1627 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1628 RegCloseKey(hkey);
1630 ClosePrinter(hprn);
1635 HeapFree(GetProcessHeap(), 0, pi);
1639 #ifdef SONAME_LIBCUPS
1640 done = CUPS_LoadPrinters();
1641 #endif
1643 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1644 PRINTCAP_LoadPrinters();
1646 /* Now enumerate the list again and delete any printers that are still tagged */
1647 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1648 if(needed) {
1649 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1650 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1651 for(i = 0; i < num; i++) {
1652 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1653 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1654 BOOL delete_driver = FALSE;
1655 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1656 DWORD dw, type, size = sizeof(dw);
1657 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1658 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1659 DeletePrinter(hprn);
1660 delete_driver = TRUE;
1662 RegCloseKey(hkey);
1664 ClosePrinter(hprn);
1665 if(delete_driver)
1666 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1671 HeapFree(GetProcessHeap(), 0, pi);
1674 return;
1678 /******************************************************************
1679 * get_job
1681 * Get the pointer to the specified job.
1682 * Should hold the printer_handles_cs before calling.
1684 static job_t *get_job(HANDLE hprn, DWORD JobId)
1686 opened_printer_t *printer = get_opened_printer(hprn);
1687 job_t *job;
1689 if(!printer) return NULL;
1690 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1692 if(job->job_id == JobId)
1693 return job;
1695 return NULL;
1698 /***********************************************************
1699 * DEVMODEcpyAtoW
1701 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1703 BOOL Formname;
1704 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1705 DWORD size;
1707 Formname = (dmA->dmSize > off_formname);
1708 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1709 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1710 dmW->dmDeviceName, CCHDEVICENAME);
1711 if(!Formname) {
1712 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1713 dmA->dmSize - CCHDEVICENAME);
1714 } else {
1715 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1716 off_formname - CCHDEVICENAME);
1717 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1718 dmW->dmFormName, CCHFORMNAME);
1719 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1720 (off_formname + CCHFORMNAME));
1722 dmW->dmSize = size;
1723 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1724 dmA->dmDriverExtra);
1725 return dmW;
1728 /***********************************************************
1729 * DEVMODEdupWtoA
1730 * Creates an ansi copy of supplied devmode
1732 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1734 LPDEVMODEA dmA;
1735 DWORD size;
1737 if (!dmW) return NULL;
1738 size = dmW->dmSize - CCHDEVICENAME -
1739 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1741 dmA = HeapAlloc(GetProcessHeap(), 0, size + dmW->dmDriverExtra);
1742 if (!dmA) return NULL;
1744 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1745 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1747 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1748 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1749 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1751 else
1753 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1754 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1755 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1756 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1758 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1761 dmA->dmSize = size;
1762 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1763 return dmA;
1766 /******************************************************************
1767 * convert_printerinfo_W_to_A [internal]
1770 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1771 DWORD level, DWORD outlen, DWORD numentries)
1773 DWORD id = 0;
1774 LPSTR ptr;
1775 INT len;
1777 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1779 len = pi_sizeof[level] * numentries;
1780 ptr = (LPSTR) out + len;
1781 outlen -= len;
1783 /* copy the numbers of all PRINTER_INFO_* first */
1784 memcpy(out, pPrintersW, len);
1786 while (id < numentries) {
1787 switch (level) {
1788 case 1:
1790 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1791 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1793 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1794 if (piW->pDescription) {
1795 piA->pDescription = ptr;
1796 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1797 ptr, outlen, NULL, NULL);
1798 ptr += len;
1799 outlen -= len;
1801 if (piW->pName) {
1802 piA->pName = ptr;
1803 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1804 ptr, outlen, NULL, NULL);
1805 ptr += len;
1806 outlen -= len;
1808 if (piW->pComment) {
1809 piA->pComment = ptr;
1810 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1811 ptr, outlen, NULL, NULL);
1812 ptr += len;
1813 outlen -= len;
1815 break;
1818 case 2:
1820 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1821 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1822 LPDEVMODEA dmA;
1824 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1825 if (piW->pServerName) {
1826 piA->pServerName = ptr;
1827 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1828 ptr, outlen, NULL, NULL);
1829 ptr += len;
1830 outlen -= len;
1832 if (piW->pPrinterName) {
1833 piA->pPrinterName = ptr;
1834 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1835 ptr, outlen, NULL, NULL);
1836 ptr += len;
1837 outlen -= len;
1839 if (piW->pShareName) {
1840 piA->pShareName = ptr;
1841 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1842 ptr, outlen, NULL, NULL);
1843 ptr += len;
1844 outlen -= len;
1846 if (piW->pPortName) {
1847 piA->pPortName = ptr;
1848 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1849 ptr, outlen, NULL, NULL);
1850 ptr += len;
1851 outlen -= len;
1853 if (piW->pDriverName) {
1854 piA->pDriverName = ptr;
1855 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1856 ptr, outlen, NULL, NULL);
1857 ptr += len;
1858 outlen -= len;
1860 if (piW->pComment) {
1861 piA->pComment = ptr;
1862 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1863 ptr, outlen, NULL, NULL);
1864 ptr += len;
1865 outlen -= len;
1867 if (piW->pLocation) {
1868 piA->pLocation = ptr;
1869 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1870 ptr, outlen, NULL, NULL);
1871 ptr += len;
1872 outlen -= len;
1875 dmA = DEVMODEdupWtoA(piW->pDevMode);
1876 if (dmA) {
1877 /* align DEVMODEA to a DWORD boundary */
1878 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1879 ptr += len;
1880 outlen -= len;
1882 piA->pDevMode = (LPDEVMODEA) ptr;
1883 len = dmA->dmSize + dmA->dmDriverExtra;
1884 memcpy(ptr, dmA, len);
1885 HeapFree(GetProcessHeap(), 0, dmA);
1887 ptr += len;
1888 outlen -= len;
1891 if (piW->pSepFile) {
1892 piA->pSepFile = ptr;
1893 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1894 ptr, outlen, NULL, NULL);
1895 ptr += len;
1896 outlen -= len;
1898 if (piW->pPrintProcessor) {
1899 piA->pPrintProcessor = ptr;
1900 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1901 ptr, outlen, NULL, NULL);
1902 ptr += len;
1903 outlen -= len;
1905 if (piW->pDatatype) {
1906 piA->pDatatype = ptr;
1907 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1908 ptr, outlen, NULL, NULL);
1909 ptr += len;
1910 outlen -= len;
1912 if (piW->pParameters) {
1913 piA->pParameters = ptr;
1914 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1915 ptr, outlen, NULL, NULL);
1916 ptr += len;
1917 outlen -= len;
1919 if (piW->pSecurityDescriptor) {
1920 piA->pSecurityDescriptor = NULL;
1921 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1923 break;
1926 case 4:
1928 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1929 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1931 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1933 if (piW->pPrinterName) {
1934 piA->pPrinterName = ptr;
1935 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1936 ptr, outlen, NULL, NULL);
1937 ptr += len;
1938 outlen -= len;
1940 if (piW->pServerName) {
1941 piA->pServerName = ptr;
1942 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1943 ptr, outlen, NULL, NULL);
1944 ptr += len;
1945 outlen -= len;
1947 break;
1950 case 5:
1952 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1953 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1955 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1957 if (piW->pPrinterName) {
1958 piA->pPrinterName = ptr;
1959 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1960 ptr, outlen, NULL, NULL);
1961 ptr += len;
1962 outlen -= len;
1964 if (piW->pPortName) {
1965 piA->pPortName = ptr;
1966 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1967 ptr, outlen, NULL, NULL);
1968 ptr += len;
1969 outlen -= len;
1971 break;
1974 default:
1975 FIXME("for level %u\n", level);
1977 pPrintersW += pi_sizeof[level];
1978 out += pi_sizeof[level];
1979 id++;
1983 /***********************************************************
1984 * PRINTER_INFO_2AtoW
1985 * Creates a unicode copy of PRINTER_INFO_2A on heap
1987 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1989 LPPRINTER_INFO_2W piW;
1990 UNICODE_STRING usBuffer;
1992 if(!piA) return NULL;
1993 piW = HeapAlloc(heap, 0, sizeof(*piW));
1994 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1996 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1997 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1998 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1999 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
2000 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
2001 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
2002 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
2003 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
2004 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
2005 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
2006 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
2007 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
2008 return piW;
2011 /***********************************************************
2012 * FREE_PRINTER_INFO_2W
2013 * Free PRINTER_INFO_2W and all strings
2015 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
2017 if(!piW) return;
2019 HeapFree(heap,0,piW->pServerName);
2020 HeapFree(heap,0,piW->pPrinterName);
2021 HeapFree(heap,0,piW->pShareName);
2022 HeapFree(heap,0,piW->pPortName);
2023 HeapFree(heap,0,piW->pDriverName);
2024 HeapFree(heap,0,piW->pComment);
2025 HeapFree(heap,0,piW->pLocation);
2026 HeapFree(heap,0,piW->pDevMode);
2027 HeapFree(heap,0,piW->pSepFile);
2028 HeapFree(heap,0,piW->pPrintProcessor);
2029 HeapFree(heap,0,piW->pDatatype);
2030 HeapFree(heap,0,piW->pParameters);
2031 HeapFree(heap,0,piW);
2032 return;
2035 /******************************************************************
2036 * DeviceCapabilities [WINSPOOL.@]
2037 * DeviceCapabilitiesA [WINSPOOL.@]
2040 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
2041 LPSTR pOutput, LPDEVMODEA lpdm)
2043 INT ret;
2045 if (!GDI_CallDeviceCapabilities16)
2047 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2048 (LPCSTR)104 );
2049 if (!GDI_CallDeviceCapabilities16) return -1;
2051 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
2053 /* If DC_PAPERSIZE map POINT16s to POINTs */
2054 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
2055 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
2056 POINT *pt = (POINT *)pOutput;
2057 INT i;
2058 memcpy(tmp, pOutput, ret * sizeof(POINT16));
2059 for(i = 0; i < ret; i++, pt++)
2061 pt->x = tmp[i].x;
2062 pt->y = tmp[i].y;
2064 HeapFree( GetProcessHeap(), 0, tmp );
2066 return ret;
2070 /*****************************************************************************
2071 * DeviceCapabilitiesW [WINSPOOL.@]
2073 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2076 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
2077 WORD fwCapability, LPWSTR pOutput,
2078 const DEVMODEW *pDevMode)
2080 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
2081 LPSTR pDeviceA = strdupWtoA(pDevice);
2082 LPSTR pPortA = strdupWtoA(pPort);
2083 INT ret;
2085 if(pOutput && (fwCapability == DC_BINNAMES ||
2086 fwCapability == DC_FILEDEPENDENCIES ||
2087 fwCapability == DC_PAPERNAMES)) {
2088 /* These need A -> W translation */
2089 INT size = 0, i;
2090 LPSTR pOutputA;
2091 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2092 dmA);
2093 if(ret == -1)
2094 return ret;
2095 switch(fwCapability) {
2096 case DC_BINNAMES:
2097 size = 24;
2098 break;
2099 case DC_PAPERNAMES:
2100 case DC_FILEDEPENDENCIES:
2101 size = 64;
2102 break;
2104 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
2105 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2106 dmA);
2107 for(i = 0; i < ret; i++)
2108 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2109 pOutput + (i * size), size);
2110 HeapFree(GetProcessHeap(), 0, pOutputA);
2111 } else {
2112 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2113 (LPSTR)pOutput, dmA);
2115 HeapFree(GetProcessHeap(),0,pPortA);
2116 HeapFree(GetProcessHeap(),0,pDeviceA);
2117 HeapFree(GetProcessHeap(),0,dmA);
2118 return ret;
2121 /******************************************************************
2122 * DocumentPropertiesA [WINSPOOL.@]
2124 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2126 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
2127 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
2128 LPDEVMODEA pDevModeInput,DWORD fMode )
2130 LPSTR lpName = pDeviceName;
2131 static CHAR port[] = "LPT1:";
2132 LONG ret;
2134 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2135 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
2138 if(!pDeviceName) {
2139 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2140 if(!lpNameW) {
2141 ERR("no name from hPrinter?\n");
2142 SetLastError(ERROR_INVALID_HANDLE);
2143 return -1;
2145 lpName = strdupWtoA(lpNameW);
2148 if (!GDI_CallExtDeviceMode16)
2150 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2151 (LPCSTR)102 );
2152 if (!GDI_CallExtDeviceMode16) {
2153 ERR("No CallExtDeviceMode16?\n");
2154 return -1;
2157 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
2158 pDevModeInput, NULL, fMode);
2160 if(!pDeviceName)
2161 HeapFree(GetProcessHeap(),0,lpName);
2162 return ret;
2166 /*****************************************************************************
2167 * DocumentPropertiesW (WINSPOOL.@)
2169 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2171 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
2172 LPWSTR pDeviceName,
2173 LPDEVMODEW pDevModeOutput,
2174 LPDEVMODEW pDevModeInput, DWORD fMode)
2177 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
2178 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
2179 LPDEVMODEA pDevModeOutputA = NULL;
2180 LONG ret;
2182 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2183 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2184 fMode);
2185 if(pDevModeOutput) {
2186 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2187 if(ret < 0) return ret;
2188 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
2190 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2191 pDevModeInputA, fMode);
2192 if(pDevModeOutput) {
2193 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2194 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2196 if(fMode == 0 && ret > 0)
2197 ret += (CCHDEVICENAME + CCHFORMNAME);
2198 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2199 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2200 return ret;
2203 /******************************************************************
2204 * OpenPrinterA [WINSPOOL.@]
2206 * See OpenPrinterW.
2209 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2210 LPPRINTER_DEFAULTSA pDefault)
2212 UNICODE_STRING lpPrinterNameW;
2213 UNICODE_STRING usBuffer;
2214 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2215 PWSTR pwstrPrinterNameW;
2216 BOOL ret;
2218 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2220 if(pDefault) {
2221 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2222 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2223 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2224 pDefaultW = &DefaultW;
2226 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2227 if(pDefault) {
2228 RtlFreeUnicodeString(&usBuffer);
2229 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2231 RtlFreeUnicodeString(&lpPrinterNameW);
2232 return ret;
2235 /******************************************************************
2236 * OpenPrinterW [WINSPOOL.@]
2238 * Open a Printer / Printserver or a Printer-Object
2240 * PARAMS
2241 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2242 * phPrinter [O] The resulting Handle is stored here
2243 * pDefault [I] PTR to Default Printer Settings or NULL
2245 * RETURNS
2246 * Success: TRUE
2247 * Failure: FALSE
2249 * NOTES
2250 * lpPrinterName is one of:
2251 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2252 *| Printer: "PrinterName"
2253 *| Printer-Object: "PrinterName,Job xxx"
2254 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2255 *| XcvPort: "Servername,XcvPort PortName"
2257 * BUGS
2258 *| Printer-Object not supported
2259 *| pDefaults is ignored
2262 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2265 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2266 if (pDefault) {
2267 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2268 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
2271 if(!phPrinter) {
2272 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2273 SetLastError(ERROR_INVALID_PARAMETER);
2274 return FALSE;
2277 /* Get the unique handle of the printer or Printserver */
2278 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2279 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2280 return (*phPrinter != 0);
2283 /******************************************************************
2284 * AddMonitorA [WINSPOOL.@]
2286 * See AddMonitorW.
2289 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2291 LPWSTR nameW = NULL;
2292 INT len;
2293 BOOL res;
2294 LPMONITOR_INFO_2A mi2a;
2295 MONITOR_INFO_2W mi2w;
2297 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2298 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2299 debugstr_a(mi2a ? mi2a->pName : NULL),
2300 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2301 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2303 if (Level != 2) {
2304 SetLastError(ERROR_INVALID_LEVEL);
2305 return FALSE;
2308 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2309 if (mi2a == NULL) {
2310 return FALSE;
2313 if (pName) {
2314 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2315 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2316 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2319 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2320 if (mi2a->pName) {
2321 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2322 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2323 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2325 if (mi2a->pEnvironment) {
2326 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2327 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2328 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2330 if (mi2a->pDLLName) {
2331 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2332 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2333 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2336 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2338 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2339 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2340 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2342 HeapFree(GetProcessHeap(), 0, nameW);
2343 return (res);
2346 /******************************************************************************
2347 * AddMonitorW [WINSPOOL.@]
2349 * Install a Printmonitor
2351 * PARAMS
2352 * pName [I] Servername or NULL (local Computer)
2353 * Level [I] Structure-Level (Must be 2)
2354 * pMonitors [I] PTR to MONITOR_INFO_2
2356 * RETURNS
2357 * Success: TRUE
2358 * Failure: FALSE
2360 * NOTES
2361 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2364 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2366 monitor_t * pm = NULL;
2367 LPMONITOR_INFO_2W mi2w;
2368 HKEY hroot = NULL;
2369 HKEY hentry = NULL;
2370 DWORD disposition;
2371 BOOL res = FALSE;
2373 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2374 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2375 debugstr_w(mi2w ? mi2w->pName : NULL),
2376 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2377 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2379 if (Level != 2) {
2380 SetLastError(ERROR_INVALID_LEVEL);
2381 return FALSE;
2384 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2385 if (mi2w == NULL) {
2386 return FALSE;
2389 if (pName && (pName[0])) {
2390 FIXME("for server %s not implemented\n", debugstr_w(pName));
2391 SetLastError(ERROR_ACCESS_DENIED);
2392 return FALSE;
2396 if (!mi2w->pName || (! mi2w->pName[0])) {
2397 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
2398 SetLastError(ERROR_INVALID_PARAMETER);
2399 return FALSE;
2401 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
2402 WARN("Environment %s requested (we support only %s)\n",
2403 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
2404 SetLastError(ERROR_INVALID_ENVIRONMENT);
2405 return FALSE;
2408 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
2409 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
2410 SetLastError(ERROR_INVALID_PARAMETER);
2411 return FALSE;
2414 /* Load and initialize the monitor. SetLastError() is called on failure */
2415 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
2416 return FALSE;
2418 monitor_unload(pm);
2420 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2421 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2422 return FALSE;
2425 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
2426 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
2427 &disposition) == ERROR_SUCCESS) {
2429 /* Some installers set options for the port before calling AddMonitor.
2430 We query the "Driver" entry to verify that the monitor is installed,
2431 before we return an error.
2432 When a user installs two print monitors at the same time with the
2433 same name but with a different driver DLL and a task switch comes
2434 between RegQueryValueExW and RegSetValueExW, a race condition
2435 is possible but silently ignored. */
2437 DWORD namesize = 0;
2439 if ((disposition == REG_OPENED_EXISTING_KEY) &&
2440 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
2441 &namesize) == ERROR_SUCCESS)) {
2442 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
2443 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2444 9x: ERROR_ALREADY_EXISTS (183) */
2445 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
2447 else
2449 INT len;
2450 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
2451 res = (RegSetValueExW(hentry, DriverW, 0,
2452 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
2454 RegCloseKey(hentry);
2457 RegCloseKey(hroot);
2458 return (res);
2461 /******************************************************************
2462 * DeletePrinterDriverA [WINSPOOL.@]
2465 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2467 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2470 /******************************************************************
2471 * DeletePrinterDriverW [WINSPOOL.@]
2474 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2476 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2479 /******************************************************************
2480 * DeleteMonitorA [WINSPOOL.@]
2482 * See DeleteMonitorW.
2485 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2487 LPWSTR nameW = NULL;
2488 LPWSTR EnvironmentW = NULL;
2489 LPWSTR MonitorNameW = NULL;
2490 BOOL res;
2491 INT len;
2493 if (pName) {
2494 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2495 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2496 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2499 if (pEnvironment) {
2500 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2501 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2502 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2504 if (pMonitorName) {
2505 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2506 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2507 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2510 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2512 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2513 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2514 HeapFree(GetProcessHeap(), 0, nameW);
2515 return (res);
2518 /******************************************************************
2519 * DeleteMonitorW [WINSPOOL.@]
2521 * Delete a specific Printmonitor from a Printing-Environment
2523 * PARAMS
2524 * pName [I] Servername or NULL (local Computer)
2525 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2526 * pMonitorName [I] Name of the Monitor, that should be deleted
2528 * RETURNS
2529 * Success: TRUE
2530 * Failure: FALSE
2532 * NOTES
2533 * pEnvironment is ignored in Windows for the local Computer.
2537 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2539 HKEY hroot = NULL;
2541 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2542 debugstr_w(pMonitorName));
2544 if (pName && (pName[0])) {
2545 FIXME("for server %s not implemented\n", debugstr_w(pName));
2546 SetLastError(ERROR_ACCESS_DENIED);
2547 return FALSE;
2550 /* pEnvironment is ignored in Windows for the local Computer */
2552 if (!pMonitorName || !pMonitorName[0]) {
2553 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
2554 SetLastError(ERROR_INVALID_PARAMETER);
2555 return FALSE;
2558 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2559 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2560 return FALSE;
2563 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
2564 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
2565 RegCloseKey(hroot);
2566 return TRUE;
2569 WARN("monitor %s does not exist\n", debugstr_w(pMonitorName));
2570 RegCloseKey(hroot);
2572 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2573 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
2574 return (FALSE);
2577 /******************************************************************
2578 * DeletePortA [WINSPOOL.@]
2580 * See DeletePortW.
2583 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2585 LPWSTR nameW = NULL;
2586 LPWSTR portW = NULL;
2587 INT len;
2588 DWORD res;
2590 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2592 /* convert servername to unicode */
2593 if (pName) {
2594 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2595 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2596 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2599 /* convert portname to unicode */
2600 if (pPortName) {
2601 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2602 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2603 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2606 res = DeletePortW(nameW, hWnd, portW);
2607 HeapFree(GetProcessHeap(), 0, nameW);
2608 HeapFree(GetProcessHeap(), 0, portW);
2609 return res;
2612 /******************************************************************
2613 * DeletePortW [WINSPOOL.@]
2615 * Delete a specific Port
2617 * PARAMS
2618 * pName [I] Servername or NULL (local Computer)
2619 * hWnd [I] Handle to parent Window for the Dialog-Box
2620 * pPortName [I] Name of the Port, that should be deleted
2622 * RETURNS
2623 * Success: TRUE
2624 * Failure: FALSE
2627 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2629 monitor_t * pm;
2630 monitor_t * pui;
2631 DWORD res;
2633 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2635 if (pName && pName[0]) {
2636 SetLastError(ERROR_INVALID_PARAMETER);
2637 return FALSE;
2640 if (!pPortName) {
2641 SetLastError(RPC_X_NULL_REF_POINTER);
2642 return FALSE;
2645 /* an empty Portname is Invalid */
2646 if (!pPortName[0]) {
2647 SetLastError(ERROR_NOT_SUPPORTED);
2648 return FALSE;
2651 pm = monitor_load_by_port(pPortName);
2652 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2653 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2654 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2655 TRACE("got %d with %u\n", res, GetLastError());
2657 else
2659 pui = monitor_loadui(pm);
2660 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2661 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2662 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2663 TRACE("got %d with %u\n", res, GetLastError());
2665 else
2667 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2668 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
2670 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2671 SetLastError(ERROR_NOT_SUPPORTED);
2672 res = FALSE;
2674 monitor_unload(pui);
2676 monitor_unload(pm);
2678 TRACE("returning %d with %u\n", res, GetLastError());
2679 return res;
2682 /******************************************************************************
2683 * SetPrinterW [WINSPOOL.@]
2685 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2687 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2688 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2689 return FALSE;
2692 /******************************************************************************
2693 * WritePrinter [WINSPOOL.@]
2695 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2697 opened_printer_t *printer;
2698 BOOL ret = FALSE;
2700 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2702 EnterCriticalSection(&printer_handles_cs);
2703 printer = get_opened_printer(hPrinter);
2704 if(!printer)
2706 SetLastError(ERROR_INVALID_HANDLE);
2707 goto end;
2710 if(!printer->doc)
2712 SetLastError(ERROR_SPL_NO_STARTDOC);
2713 goto end;
2716 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2717 end:
2718 LeaveCriticalSection(&printer_handles_cs);
2719 return ret;
2722 /*****************************************************************************
2723 * AddFormA [WINSPOOL.@]
2725 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2727 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2728 return 1;
2731 /*****************************************************************************
2732 * AddFormW [WINSPOOL.@]
2734 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2736 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2737 return 1;
2740 /*****************************************************************************
2741 * AddJobA [WINSPOOL.@]
2743 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2745 BOOL ret;
2746 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2747 DWORD needed;
2749 if(Level != 1) {
2750 SetLastError(ERROR_INVALID_LEVEL);
2751 return FALSE;
2754 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2756 if(ret) {
2757 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2758 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2759 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2760 if(*pcbNeeded > cbBuf) {
2761 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2762 ret = FALSE;
2763 } else {
2764 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2765 addjobA->JobId = addjobW->JobId;
2766 addjobA->Path = (char *)(addjobA + 1);
2767 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2770 return ret;
2773 /*****************************************************************************
2774 * AddJobW [WINSPOOL.@]
2776 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2778 opened_printer_t *printer;
2779 job_t *job;
2780 BOOL ret = FALSE;
2781 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2782 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2783 WCHAR path[MAX_PATH], filename[MAX_PATH];
2784 DWORD len;
2785 ADDJOB_INFO_1W *addjob;
2787 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2789 EnterCriticalSection(&printer_handles_cs);
2791 printer = get_opened_printer(hPrinter);
2793 if(!printer) {
2794 SetLastError(ERROR_INVALID_HANDLE);
2795 goto end;
2798 if(Level != 1) {
2799 SetLastError(ERROR_INVALID_LEVEL);
2800 goto end;
2803 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2804 if(!job)
2805 goto end;
2807 job->job_id = InterlockedIncrement(&next_job_id);
2809 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2810 if(path[len - 1] != '\\')
2811 path[len++] = '\\';
2812 memcpy(path + len, spool_path, sizeof(spool_path));
2813 sprintfW(filename, fmtW, path, job->job_id);
2815 len = strlenW(filename);
2816 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2817 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2818 job->document_title = strdupW(default_doc_title);
2819 list_add_tail(&printer->queue->jobs, &job->entry);
2821 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2822 if(*pcbNeeded <= cbBuf) {
2823 addjob = (ADDJOB_INFO_1W*)pData;
2824 addjob->JobId = job->job_id;
2825 addjob->Path = (WCHAR *)(addjob + 1);
2826 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2827 ret = TRUE;
2828 } else
2829 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2831 end:
2832 LeaveCriticalSection(&printer_handles_cs);
2833 return ret;
2836 /*****************************************************************************
2837 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2839 * Return the PATH for the Print-Processors
2841 * See GetPrintProcessorDirectoryW.
2845 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2846 DWORD level, LPBYTE Info,
2847 DWORD cbBuf, LPDWORD pcbNeeded)
2849 LPWSTR serverW = NULL;
2850 LPWSTR envW = NULL;
2851 BOOL ret;
2852 INT len;
2854 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2855 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2858 if (server) {
2859 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2860 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2861 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2864 if (env) {
2865 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2866 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2867 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2870 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2871 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2873 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2874 cbBuf, pcbNeeded);
2876 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2877 cbBuf, NULL, NULL) > 0;
2880 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2881 HeapFree(GetProcessHeap(), 0, envW);
2882 HeapFree(GetProcessHeap(), 0, serverW);
2883 return ret;
2886 /*****************************************************************************
2887 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2889 * Return the PATH for the Print-Processors
2891 * PARAMS
2892 * server [I] Servername (NT only) or NULL (local Computer)
2893 * env [I] Printing-Environment (see below) or NULL (Default)
2894 * level [I] Structure-Level (must be 1)
2895 * Info [O] PTR to Buffer that receives the Result
2896 * cbBuf [I] Size of Buffer at "Info"
2897 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2898 * required for the Buffer at "Info"
2900 * RETURNS
2901 * Success: TRUE and in pcbNeeded the Bytes used in Info
2902 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2903 * if cbBuf is too small
2905 * Native Values returned in Info on Success:
2906 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2907 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2908 *| win9x(Windows 4.0): "%winsysdir%"
2910 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2912 * BUGS
2913 * Only NULL or "" is supported for server
2916 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2917 DWORD level, LPBYTE Info,
2918 DWORD cbBuf, LPDWORD pcbNeeded)
2920 DWORD needed;
2921 const printenv_t * env_t;
2923 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2924 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2926 if(server != NULL && server[0]) {
2927 FIXME("server not supported: %s\n", debugstr_w(server));
2928 SetLastError(ERROR_INVALID_PARAMETER);
2929 return FALSE;
2932 env_t = validate_envW(env);
2933 if(!env_t) return FALSE; /* environment invalid or unsupported */
2935 if(level != 1) {
2936 WARN("(Level: %d) is ignored in win9x\n", level);
2937 SetLastError(ERROR_INVALID_LEVEL);
2938 return FALSE;
2941 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2942 needed = GetSystemDirectoryW(NULL, 0);
2943 /* add the Size for the Subdirectories */
2944 needed += lstrlenW(spoolprtprocsW);
2945 needed += lstrlenW(env_t->subdir);
2946 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2948 if(pcbNeeded) *pcbNeeded = needed;
2949 TRACE ("required: 0x%x/%d\n", needed, needed);
2950 if (needed > cbBuf) {
2951 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2952 return FALSE;
2954 if(pcbNeeded == NULL) {
2955 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2956 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2957 SetLastError(RPC_X_NULL_REF_POINTER);
2958 return FALSE;
2960 if(Info == NULL) {
2961 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2962 SetLastError(RPC_X_NULL_REF_POINTER);
2963 return FALSE;
2966 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2967 /* add the Subdirectories */
2968 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2969 lstrcatW((LPWSTR) Info, env_t->subdir);
2970 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2971 return TRUE;
2974 /*****************************************************************************
2975 * WINSPOOL_OpenDriverReg [internal]
2977 * opens the registry for the printer drivers depending on the given input
2978 * variable pEnvironment
2980 * RETURNS:
2981 * the opened hkey on success
2982 * NULL on error
2984 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2986 HKEY retval = NULL;
2987 LPWSTR buffer;
2988 const printenv_t * env;
2990 TRACE("(%s, %d)\n",
2991 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2993 if (!pEnvironment || unicode) {
2994 /* pEnvironment was NULL or an Unicode-String: use it direct */
2995 env = validate_envW(pEnvironment);
2997 else
2999 /* pEnvironment was an ANSI-String: convert to unicode first */
3000 LPWSTR buffer;
3001 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
3002 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3003 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
3004 env = validate_envW(buffer);
3005 HeapFree(GetProcessHeap(), 0, buffer);
3007 if (!env) return NULL;
3009 buffer = HeapAlloc( GetProcessHeap(), 0,
3010 (strlenW(DriversW) + strlenW(env->envname) +
3011 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
3012 if(buffer) {
3013 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
3014 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
3015 HeapFree(GetProcessHeap(), 0, buffer);
3017 return retval;
3020 /*****************************************************************************
3021 * AddPrinterW [WINSPOOL.@]
3023 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
3025 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
3026 LPDEVMODEA dmA;
3027 LPDEVMODEW dmW;
3028 HANDLE retval;
3029 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
3030 LONG size;
3031 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
3032 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
3033 priorityW[] = {'P','r','i','o','r','i','t','y',0},
3034 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
3035 statusW[] = {'S','t','a','t','u','s',0},
3036 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
3038 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
3040 if(pName != NULL) {
3041 ERR("pName = %s - unsupported\n", debugstr_w(pName));
3042 SetLastError(ERROR_INVALID_PARAMETER);
3043 return 0;
3045 if(Level != 2) {
3046 ERR("Level = %d, unsupported!\n", Level);
3047 SetLastError(ERROR_INVALID_LEVEL);
3048 return 0;
3050 if(!pPrinter) {
3051 SetLastError(ERROR_INVALID_PARAMETER);
3052 return 0;
3054 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3055 ERROR_SUCCESS) {
3056 ERR("Can't create Printers key\n");
3057 return 0;
3059 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
3060 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
3061 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
3062 RegCloseKey(hkeyPrinter);
3063 RegCloseKey(hkeyPrinters);
3064 return 0;
3066 RegCloseKey(hkeyPrinter);
3068 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
3069 if(!hkeyDrivers) {
3070 ERR("Can't create Drivers key\n");
3071 RegCloseKey(hkeyPrinters);
3072 return 0;
3074 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
3075 ERROR_SUCCESS) {
3076 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
3077 RegCloseKey(hkeyPrinters);
3078 RegCloseKey(hkeyDrivers);
3079 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
3080 return 0;
3082 RegCloseKey(hkeyDriver);
3083 RegCloseKey(hkeyDrivers);
3085 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
3086 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
3087 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
3088 RegCloseKey(hkeyPrinters);
3089 return 0;
3092 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
3093 ERROR_SUCCESS) {
3094 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
3095 SetLastError(ERROR_INVALID_PRINTER_NAME);
3096 RegCloseKey(hkeyPrinters);
3097 return 0;
3099 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
3100 (LPBYTE)&pi->Attributes, sizeof(DWORD));
3101 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
3103 /* See if we can load the driver. We may need the devmode structure anyway
3105 * FIXME:
3106 * Note that DocumentPropertiesW will briefly try to open the printer we
3107 * just create to find a DEVMODEA struct (it will use the WINEPS default
3108 * one in case it is not there, so we are ok).
3110 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
3112 if(size < 0) {
3113 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
3114 size = sizeof(DEVMODEW);
3116 if(pi->pDevMode)
3117 dmW = pi->pDevMode;
3118 else
3120 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
3121 dmW->dmSize = size;
3122 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
3124 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
3125 HeapFree(GetProcessHeap(),0,dmW);
3126 dmW=NULL;
3128 else
3130 /* set devmode to printer name */
3131 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
3135 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
3136 and we support these drivers. NT writes DEVMODEW so somehow
3137 we'll need to distinguish between these when we support NT
3138 drivers */
3139 if (dmW)
3141 dmA = DEVMODEdupWtoA(dmW);
3142 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
3143 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
3144 HeapFree(GetProcessHeap(), 0, dmA);
3145 if(!pi->pDevMode)
3146 HeapFree(GetProcessHeap(), 0, dmW);
3148 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
3149 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
3150 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
3151 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
3153 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
3154 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
3155 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
3156 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
3157 (LPBYTE)&pi->Priority, sizeof(DWORD));
3158 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
3159 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
3160 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
3161 (LPBYTE)&pi->StartTime, sizeof(DWORD));
3162 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
3163 (LPBYTE)&pi->Status, sizeof(DWORD));
3164 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
3165 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
3167 RegCloseKey(hkeyPrinter);
3168 RegCloseKey(hkeyPrinters);
3169 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
3170 ERR("OpenPrinter failing\n");
3171 return 0;
3173 return retval;
3176 /*****************************************************************************
3177 * AddPrinterA [WINSPOOL.@]
3179 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
3181 UNICODE_STRING pNameW;
3182 PWSTR pwstrNameW;
3183 PRINTER_INFO_2W *piW;
3184 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
3185 HANDLE ret;
3187 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
3188 if(Level != 2) {
3189 ERR("Level = %d, unsupported!\n", Level);
3190 SetLastError(ERROR_INVALID_LEVEL);
3191 return 0;
3193 pwstrNameW = asciitounicode(&pNameW,pName);
3194 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
3196 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3198 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
3199 RtlFreeUnicodeString(&pNameW);
3200 return ret;
3204 /*****************************************************************************
3205 * ClosePrinter [WINSPOOL.@]
3207 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3209 UINT_PTR i = (UINT_PTR)hPrinter;
3210 opened_printer_t *printer = NULL;
3211 BOOL ret = FALSE;
3213 TRACE("(%p)\n", hPrinter);
3215 EnterCriticalSection(&printer_handles_cs);
3217 if ((i > 0) && (i <= nb_printer_handles))
3218 printer = printer_handles[i - 1];
3221 if(printer)
3223 struct list *cursor, *cursor2;
3225 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer->pm,
3226 debugstr_w(printer->pm ? printer->pm->dllname : NULL),
3227 printer->hXcv, debugstr_w(printer->name), printer->doc );
3229 if(printer->doc)
3230 EndDocPrinter(hPrinter);
3232 if(InterlockedDecrement(&printer->queue->ref) == 0)
3234 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3236 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3237 ScheduleJob(hPrinter, job->job_id);
3239 HeapFree(GetProcessHeap(), 0, printer->queue);
3241 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
3242 monitor_unload(printer->pm);
3243 HeapFree(GetProcessHeap(), 0, printer->printername);
3244 HeapFree(GetProcessHeap(), 0, printer->name);
3245 HeapFree(GetProcessHeap(), 0, printer);
3246 printer_handles[i - 1] = NULL;
3247 ret = TRUE;
3249 LeaveCriticalSection(&printer_handles_cs);
3250 return ret;
3253 /*****************************************************************************
3254 * DeleteFormA [WINSPOOL.@]
3256 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3258 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3259 return 1;
3262 /*****************************************************************************
3263 * DeleteFormW [WINSPOOL.@]
3265 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3267 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3268 return 1;
3271 /*****************************************************************************
3272 * DeletePrinter [WINSPOOL.@]
3274 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3276 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3277 HKEY hkeyPrinters, hkey;
3279 if(!lpNameW) {
3280 SetLastError(ERROR_INVALID_HANDLE);
3281 return FALSE;
3283 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3284 RegDeleteTreeW(hkeyPrinters, lpNameW);
3285 RegCloseKey(hkeyPrinters);
3287 WriteProfileStringW(devicesW, lpNameW, NULL);
3288 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
3290 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3291 RegDeleteValueW(hkey, lpNameW);
3292 RegCloseKey(hkey);
3295 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
3296 RegDeleteValueW(hkey, lpNameW);
3297 RegCloseKey(hkey);
3299 return TRUE;
3302 /*****************************************************************************
3303 * SetPrinterA [WINSPOOL.@]
3305 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3306 DWORD Command)
3308 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
3309 return FALSE;
3312 /*****************************************************************************
3313 * SetJobA [WINSPOOL.@]
3315 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3316 LPBYTE pJob, DWORD Command)
3318 BOOL ret;
3319 LPBYTE JobW;
3320 UNICODE_STRING usBuffer;
3322 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3324 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3325 are all ignored by SetJob, so we don't bother copying them */
3326 switch(Level)
3328 case 0:
3329 JobW = NULL;
3330 break;
3331 case 1:
3333 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3334 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3336 JobW = (LPBYTE)info1W;
3337 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3338 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3339 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3340 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3341 info1W->Status = info1A->Status;
3342 info1W->Priority = info1A->Priority;
3343 info1W->Position = info1A->Position;
3344 info1W->PagesPrinted = info1A->PagesPrinted;
3345 break;
3347 case 2:
3349 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3350 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3352 JobW = (LPBYTE)info2W;
3353 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3354 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3355 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3356 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3357 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3358 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3359 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3360 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3361 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3362 info2W->Status = info2A->Status;
3363 info2W->Priority = info2A->Priority;
3364 info2W->Position = info2A->Position;
3365 info2W->StartTime = info2A->StartTime;
3366 info2W->UntilTime = info2A->UntilTime;
3367 info2W->PagesPrinted = info2A->PagesPrinted;
3368 break;
3370 case 3:
3371 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3372 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3373 break;
3374 default:
3375 SetLastError(ERROR_INVALID_LEVEL);
3376 return FALSE;
3379 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3381 switch(Level)
3383 case 1:
3385 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3386 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3387 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3388 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3389 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3390 break;
3392 case 2:
3394 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3395 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3396 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3397 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3398 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3399 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3400 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3401 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3402 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3403 break;
3406 HeapFree(GetProcessHeap(), 0, JobW);
3408 return ret;
3411 /*****************************************************************************
3412 * SetJobW [WINSPOOL.@]
3414 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3415 LPBYTE pJob, DWORD Command)
3417 BOOL ret = FALSE;
3418 job_t *job;
3420 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3421 FIXME("Ignoring everything other than document title\n");
3423 EnterCriticalSection(&printer_handles_cs);
3424 job = get_job(hPrinter, JobId);
3425 if(!job)
3426 goto end;
3428 switch(Level)
3430 case 0:
3431 break;
3432 case 1:
3434 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3435 HeapFree(GetProcessHeap(), 0, job->document_title);
3436 job->document_title = strdupW(info1->pDocument);
3437 break;
3439 case 2:
3441 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3442 HeapFree(GetProcessHeap(), 0, job->document_title);
3443 job->document_title = strdupW(info2->pDocument);
3444 break;
3446 case 3:
3447 break;
3448 default:
3449 SetLastError(ERROR_INVALID_LEVEL);
3450 goto end;
3452 ret = TRUE;
3453 end:
3454 LeaveCriticalSection(&printer_handles_cs);
3455 return ret;
3458 /*****************************************************************************
3459 * EndDocPrinter [WINSPOOL.@]
3461 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3463 opened_printer_t *printer;
3464 BOOL ret = FALSE;
3465 TRACE("(%p)\n", hPrinter);
3467 EnterCriticalSection(&printer_handles_cs);
3469 printer = get_opened_printer(hPrinter);
3470 if(!printer)
3472 SetLastError(ERROR_INVALID_HANDLE);
3473 goto end;
3476 if(!printer->doc)
3478 SetLastError(ERROR_SPL_NO_STARTDOC);
3479 goto end;
3482 CloseHandle(printer->doc->hf);
3483 ScheduleJob(hPrinter, printer->doc->job_id);
3484 HeapFree(GetProcessHeap(), 0, printer->doc);
3485 printer->doc = NULL;
3486 ret = TRUE;
3487 end:
3488 LeaveCriticalSection(&printer_handles_cs);
3489 return ret;
3492 /*****************************************************************************
3493 * EndPagePrinter [WINSPOOL.@]
3495 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3497 FIXME("(%p): stub\n", hPrinter);
3498 return TRUE;
3501 /*****************************************************************************
3502 * StartDocPrinterA [WINSPOOL.@]
3504 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3506 UNICODE_STRING usBuffer;
3507 DOC_INFO_2W doc2W;
3508 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3509 DWORD ret;
3511 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3512 or one (DOC_INFO_3) extra DWORDs */
3514 switch(Level) {
3515 case 2:
3516 doc2W.JobId = doc2->JobId;
3517 /* fall through */
3518 case 3:
3519 doc2W.dwMode = doc2->dwMode;
3520 /* fall through */
3521 case 1:
3522 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3523 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3524 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3525 break;
3527 default:
3528 SetLastError(ERROR_INVALID_LEVEL);
3529 return FALSE;
3532 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3534 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3535 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3536 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3538 return ret;
3541 /*****************************************************************************
3542 * StartDocPrinterW [WINSPOOL.@]
3544 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3546 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3547 opened_printer_t *printer;
3548 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3549 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3550 JOB_INFO_1W job_info;
3551 DWORD needed, ret = 0;
3552 HANDLE hf;
3553 WCHAR *filename;
3555 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3556 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3557 debugstr_w(doc->pDatatype));
3559 if(Level < 1 || Level > 3)
3561 SetLastError(ERROR_INVALID_LEVEL);
3562 return 0;
3565 EnterCriticalSection(&printer_handles_cs);
3566 printer = get_opened_printer(hPrinter);
3567 if(!printer)
3569 SetLastError(ERROR_INVALID_HANDLE);
3570 goto end;
3573 if(printer->doc)
3575 SetLastError(ERROR_INVALID_PRINTER_STATE);
3576 goto end;
3579 /* Even if we're printing to a file we still add a print job, we'll
3580 just ignore the spool file name */
3582 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3584 ERR("AddJob failed gle %u\n", GetLastError());
3585 goto end;
3588 if(doc->pOutputFile)
3589 filename = doc->pOutputFile;
3590 else
3591 filename = addjob->Path;
3593 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3594 if(hf == INVALID_HANDLE_VALUE)
3595 goto end;
3597 memset(&job_info, 0, sizeof(job_info));
3598 job_info.pDocument = doc->pDocName;
3599 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3601 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3602 printer->doc->hf = hf;
3603 ret = printer->doc->job_id = addjob->JobId;
3604 end:
3605 LeaveCriticalSection(&printer_handles_cs);
3607 return ret;
3610 /*****************************************************************************
3611 * StartPagePrinter [WINSPOOL.@]
3613 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3615 FIXME("(%p): stub\n", hPrinter);
3616 return TRUE;
3619 /*****************************************************************************
3620 * GetFormA [WINSPOOL.@]
3622 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3623 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3625 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3626 Level,pForm,cbBuf,pcbNeeded);
3627 return FALSE;
3630 /*****************************************************************************
3631 * GetFormW [WINSPOOL.@]
3633 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3634 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3636 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3637 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3638 return FALSE;
3641 /*****************************************************************************
3642 * SetFormA [WINSPOOL.@]
3644 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3645 LPBYTE pForm)
3647 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3648 return FALSE;
3651 /*****************************************************************************
3652 * SetFormW [WINSPOOL.@]
3654 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3655 LPBYTE pForm)
3657 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3658 return FALSE;
3661 /*****************************************************************************
3662 * ReadPrinter [WINSPOOL.@]
3664 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3665 LPDWORD pNoBytesRead)
3667 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3668 return FALSE;
3671 /*****************************************************************************
3672 * ResetPrinterA [WINSPOOL.@]
3674 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3676 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3677 return FALSE;
3680 /*****************************************************************************
3681 * ResetPrinterW [WINSPOOL.@]
3683 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3685 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3686 return FALSE;
3689 /*****************************************************************************
3690 * WINSPOOL_GetDWORDFromReg
3692 * Return DWORD associated with ValueName from hkey.
3694 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3696 DWORD sz = sizeof(DWORD), type, value = 0;
3697 LONG ret;
3699 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3701 if(ret != ERROR_SUCCESS) {
3702 WARN("Got ret = %d on name %s\n", ret, ValueName);
3703 return 0;
3705 if(type != REG_DWORD) {
3706 ERR("Got type %d\n", type);
3707 return 0;
3709 return value;
3713 /*****************************************************************************
3714 * get_filename_from_reg [internal]
3716 * Get ValueName from hkey storing result in out
3717 * when the Value in the registry has only a filename, use driverdir as prefix
3718 * outlen is space left in out
3719 * String is stored either as unicode or ascii
3723 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3724 LPBYTE out, DWORD outlen, LPDWORD needed, BOOL unicode)
3726 WCHAR filename[MAX_PATH];
3727 DWORD size;
3728 DWORD type;
3729 LONG ret;
3730 LPWSTR buffer = filename;
3731 LPWSTR ptr;
3733 *needed = 0;
3734 size = sizeof(filename);
3735 buffer[0] = '\0';
3736 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3737 if (ret == ERROR_MORE_DATA) {
3738 TRACE("need dynamic buffer: %u\n", size);
3739 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3740 if (!buffer) {
3741 /* No Memory is bad */
3742 return FALSE;
3744 buffer[0] = '\0';
3745 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3748 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3749 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3750 return FALSE;
3753 ptr = buffer;
3754 while (ptr) {
3755 /* do we have a full path ? */
3756 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3757 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3759 if (!ret) {
3760 /* we must build the full Path */
3761 *needed += dirlen;
3762 if ((out) && (outlen > dirlen)) {
3763 if (unicode) {
3764 lstrcpyW((LPWSTR)out, driverdir);
3766 else
3768 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, (LPSTR)out, outlen, NULL, NULL);
3770 out += dirlen;
3771 outlen -= dirlen;
3773 else
3774 out = NULL;
3777 /* write the filename */
3778 if (unicode) {
3779 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3780 if ((out) && (outlen >= size)) {
3781 lstrcpyW((LPWSTR)out, ptr);
3782 out += size;
3783 outlen -= size;
3785 else
3786 out = NULL;
3788 else
3790 size = WideCharToMultiByte(CP_ACP, 0, ptr, -1, NULL, 0, NULL, NULL);
3791 if ((out) && (outlen >= size)) {
3792 WideCharToMultiByte(CP_ACP, 0, ptr, -1, (LPSTR)out, outlen, NULL, NULL);
3793 out += size;
3794 outlen -= size;
3796 else
3797 out = NULL;
3799 *needed += size;
3800 ptr += lstrlenW(ptr)+1;
3801 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3804 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3806 /* write the multisz-termination */
3807 if (type == REG_MULTI_SZ) {
3808 size = (unicode) ? sizeof(WCHAR) : 1;
3810 *needed += size;
3811 if (out && (outlen >= size)) {
3812 memset (out, 0, size);
3815 return TRUE;
3818 /*****************************************************************************
3819 * WINSPOOL_GetStringFromReg
3821 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3822 * String is stored either as unicode or ascii.
3823 * Bit of a hack here to get the ValueName if we want ascii.
3825 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3826 DWORD buflen, DWORD *needed,
3827 BOOL unicode)
3829 DWORD sz = buflen, type;
3830 LONG ret;
3832 if(unicode)
3833 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3834 else {
3835 LPSTR ValueNameA = strdupWtoA(ValueName);
3836 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3837 HeapFree(GetProcessHeap(),0,ValueNameA);
3839 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3840 WARN("Got ret = %d\n", ret);
3841 *needed = 0;
3842 return FALSE;
3844 /* add space for terminating '\0' */
3845 sz += unicode ? sizeof(WCHAR) : 1;
3846 *needed = sz;
3848 if (ptr)
3849 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3851 return TRUE;
3854 /*****************************************************************************
3855 * WINSPOOL_GetDefaultDevMode
3857 * Get a default DevMode values for wineps.
3858 * FIXME - use ppd.
3861 static void WINSPOOL_GetDefaultDevMode(
3862 LPBYTE ptr,
3863 DWORD buflen, DWORD *needed,
3864 BOOL unicode)
3866 DEVMODEA dm;
3867 static const char szwps[] = "wineps.drv";
3869 /* fill default DEVMODE - should be read from ppd... */
3870 ZeroMemory( &dm, sizeof(dm) );
3871 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3872 dm.dmSpecVersion = DM_SPECVERSION;
3873 dm.dmDriverVersion = 1;
3874 dm.dmSize = sizeof(DEVMODEA);
3875 dm.dmDriverExtra = 0;
3876 dm.dmFields =
3877 DM_ORIENTATION | DM_PAPERSIZE |
3878 DM_PAPERLENGTH | DM_PAPERWIDTH |
3879 DM_SCALE |
3880 DM_COPIES |
3881 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3882 DM_YRESOLUTION | DM_TTOPTION;
3884 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3885 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3886 dm.u1.s1.dmPaperLength = 2970;
3887 dm.u1.s1.dmPaperWidth = 2100;
3889 dm.u1.s1.dmScale = 100;
3890 dm.u1.s1.dmCopies = 1;
3891 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3892 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3893 /* dm.dmColor */
3894 /* dm.dmDuplex */
3895 dm.dmYResolution = 300; /* 300dpi */
3896 dm.dmTTOption = DMTT_BITMAP;
3897 /* dm.dmCollate */
3898 /* dm.dmFormName */
3899 /* dm.dmLogPixels */
3900 /* dm.dmBitsPerPel */
3901 /* dm.dmPelsWidth */
3902 /* dm.dmPelsHeight */
3903 /* dm.u2.dmDisplayFlags */
3904 /* dm.dmDisplayFrequency */
3905 /* dm.dmICMMethod */
3906 /* dm.dmICMIntent */
3907 /* dm.dmMediaType */
3908 /* dm.dmDitherType */
3909 /* dm.dmReserved1 */
3910 /* dm.dmReserved2 */
3911 /* dm.dmPanningWidth */
3912 /* dm.dmPanningHeight */
3914 if(unicode) {
3915 if(buflen >= sizeof(DEVMODEW)) {
3916 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3917 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3918 HeapFree(GetProcessHeap(),0,pdmW);
3920 *needed = sizeof(DEVMODEW);
3922 else
3924 if(buflen >= sizeof(DEVMODEA)) {
3925 memcpy(ptr, &dm, sizeof(DEVMODEA));
3927 *needed = sizeof(DEVMODEA);
3931 /*****************************************************************************
3932 * WINSPOOL_GetDevModeFromReg
3934 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3935 * DevMode is stored either as unicode or ascii.
3937 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3938 LPBYTE ptr,
3939 DWORD buflen, DWORD *needed,
3940 BOOL unicode)
3942 DWORD sz = buflen, type;
3943 LONG ret;
3945 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3946 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3947 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3948 if (sz < sizeof(DEVMODEA))
3950 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3951 return FALSE;
3953 /* ensures that dmSize is not erratically bogus if registry is invalid */
3954 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3955 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3956 if(unicode) {
3957 sz += (CCHDEVICENAME + CCHFORMNAME);
3958 if(buflen >= sz) {
3959 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3960 memcpy(ptr, dmW, sz);
3961 HeapFree(GetProcessHeap(),0,dmW);
3964 *needed = sz;
3965 return TRUE;
3968 /*********************************************************************
3969 * WINSPOOL_GetPrinter_1
3971 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3972 * The strings are either stored as unicode or ascii.
3974 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3975 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3976 BOOL unicode)
3978 DWORD size, left = cbBuf;
3979 BOOL space = (cbBuf > 0);
3980 LPBYTE ptr = buf;
3982 *pcbNeeded = 0;
3984 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3985 unicode)) {
3986 if(space && size <= left) {
3987 pi1->pName = (LPWSTR)ptr;
3988 ptr += size;
3989 left -= size;
3990 } else
3991 space = FALSE;
3992 *pcbNeeded += size;
3995 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3996 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3997 unicode)) {
3998 if(space && size <= left) {
3999 pi1->pDescription = (LPWSTR)ptr;
4000 ptr += size;
4001 left -= size;
4002 } else
4003 space = FALSE;
4004 *pcbNeeded += size;
4007 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
4008 unicode)) {
4009 if(space && size <= left) {
4010 pi1->pComment = (LPWSTR)ptr;
4011 ptr += size;
4012 left -= size;
4013 } else
4014 space = FALSE;
4015 *pcbNeeded += size;
4018 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
4020 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
4021 memset(pi1, 0, sizeof(*pi1));
4023 return space;
4025 /*********************************************************************
4026 * WINSPOOL_GetPrinter_2
4028 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
4029 * The strings are either stored as unicode or ascii.
4031 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
4032 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
4033 BOOL unicode)
4035 DWORD size, left = cbBuf;
4036 BOOL space = (cbBuf > 0);
4037 LPBYTE ptr = buf;
4039 *pcbNeeded = 0;
4041 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
4042 unicode)) {
4043 if(space && size <= left) {
4044 pi2->pPrinterName = (LPWSTR)ptr;
4045 ptr += size;
4046 left -= size;
4047 } else
4048 space = FALSE;
4049 *pcbNeeded += size;
4051 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
4052 unicode)) {
4053 if(space && size <= left) {
4054 pi2->pShareName = (LPWSTR)ptr;
4055 ptr += size;
4056 left -= size;
4057 } else
4058 space = FALSE;
4059 *pcbNeeded += size;
4061 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
4062 unicode)) {
4063 if(space && size <= left) {
4064 pi2->pPortName = (LPWSTR)ptr;
4065 ptr += size;
4066 left -= size;
4067 } else
4068 space = FALSE;
4069 *pcbNeeded += size;
4071 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
4072 &size, unicode)) {
4073 if(space && size <= left) {
4074 pi2->pDriverName = (LPWSTR)ptr;
4075 ptr += size;
4076 left -= size;
4077 } else
4078 space = FALSE;
4079 *pcbNeeded += size;
4081 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
4082 unicode)) {
4083 if(space && size <= left) {
4084 pi2->pComment = (LPWSTR)ptr;
4085 ptr += size;
4086 left -= size;
4087 } else
4088 space = FALSE;
4089 *pcbNeeded += size;
4091 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
4092 unicode)) {
4093 if(space && size <= left) {
4094 pi2->pLocation = (LPWSTR)ptr;
4095 ptr += size;
4096 left -= size;
4097 } else
4098 space = FALSE;
4099 *pcbNeeded += size;
4101 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
4102 &size, unicode)) {
4103 if(space && size <= left) {
4104 pi2->pDevMode = (LPDEVMODEW)ptr;
4105 ptr += size;
4106 left -= size;
4107 } else
4108 space = FALSE;
4109 *pcbNeeded += size;
4111 else
4113 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
4114 if(space && size <= left) {
4115 pi2->pDevMode = (LPDEVMODEW)ptr;
4116 ptr += size;
4117 left -= size;
4118 } else
4119 space = FALSE;
4120 *pcbNeeded += size;
4122 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
4123 &size, unicode)) {
4124 if(space && size <= left) {
4125 pi2->pSepFile = (LPWSTR)ptr;
4126 ptr += size;
4127 left -= size;
4128 } else
4129 space = FALSE;
4130 *pcbNeeded += size;
4132 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
4133 &size, unicode)) {
4134 if(space && size <= left) {
4135 pi2->pPrintProcessor = (LPWSTR)ptr;
4136 ptr += size;
4137 left -= size;
4138 } else
4139 space = FALSE;
4140 *pcbNeeded += size;
4142 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
4143 &size, unicode)) {
4144 if(space && size <= left) {
4145 pi2->pDatatype = (LPWSTR)ptr;
4146 ptr += size;
4147 left -= size;
4148 } else
4149 space = FALSE;
4150 *pcbNeeded += size;
4152 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
4153 &size, unicode)) {
4154 if(space && size <= left) {
4155 pi2->pParameters = (LPWSTR)ptr;
4156 ptr += size;
4157 left -= size;
4158 } else
4159 space = FALSE;
4160 *pcbNeeded += size;
4162 if(pi2) {
4163 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
4164 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
4165 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
4166 "Default Priority");
4167 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
4168 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
4171 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
4172 memset(pi2, 0, sizeof(*pi2));
4174 return space;
4177 /*********************************************************************
4178 * WINSPOOL_GetPrinter_4
4180 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4182 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
4183 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
4184 BOOL unicode)
4186 DWORD size, left = cbBuf;
4187 BOOL space = (cbBuf > 0);
4188 LPBYTE ptr = buf;
4190 *pcbNeeded = 0;
4192 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
4193 unicode)) {
4194 if(space && size <= left) {
4195 pi4->pPrinterName = (LPWSTR)ptr;
4196 ptr += size;
4197 left -= size;
4198 } else
4199 space = FALSE;
4200 *pcbNeeded += size;
4202 if(pi4) {
4203 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
4206 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4207 memset(pi4, 0, sizeof(*pi4));
4209 return space;
4212 /*********************************************************************
4213 * WINSPOOL_GetPrinter_5
4215 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4217 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4218 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
4219 BOOL unicode)
4221 DWORD size, left = cbBuf;
4222 BOOL space = (cbBuf > 0);
4223 LPBYTE ptr = buf;
4225 *pcbNeeded = 0;
4227 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
4228 unicode)) {
4229 if(space && size <= left) {
4230 pi5->pPrinterName = (LPWSTR)ptr;
4231 ptr += size;
4232 left -= size;
4233 } else
4234 space = FALSE;
4235 *pcbNeeded += size;
4237 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
4238 unicode)) {
4239 if(space && size <= left) {
4240 pi5->pPortName = (LPWSTR)ptr;
4241 ptr += size;
4242 left -= size;
4243 } else
4244 space = FALSE;
4245 *pcbNeeded += size;
4247 if(pi5) {
4248 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
4249 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
4250 "dnsTimeout");
4251 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
4252 "txTimeout");
4255 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4256 memset(pi5, 0, sizeof(*pi5));
4258 return space;
4261 /*********************************************************************
4262 * WINSPOOL_GetPrinter_7
4264 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4266 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4267 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4269 DWORD size, left = cbBuf;
4270 BOOL space = (cbBuf > 0);
4271 LPBYTE ptr = buf;
4273 *pcbNeeded = 0;
4275 if (WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size, unicode))
4277 if (space && size <= left) {
4278 pi7->pszObjectGUID = (LPWSTR)ptr;
4279 ptr += size;
4280 left -= size;
4281 } else
4282 space = FALSE;
4283 *pcbNeeded += size;
4285 if (pi7) {
4286 /* We do not have a Directory Service */
4287 pi7->dwAction = DSPRINT_UNPUBLISH;
4290 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4291 memset(pi7, 0, sizeof(*pi7));
4293 return space;
4296 /*********************************************************************
4297 * WINSPOOL_GetPrinter_9
4299 * Fills out a PRINTER_INFO_9A|W struct storing the strings in buf.
4300 * The strings are either stored as unicode or ascii.
4302 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4303 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4305 DWORD size;
4306 BOOL space = (cbBuf > 0);
4308 *pcbNeeded = 0;
4310 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size, unicode)) {
4311 if(space && size <= cbBuf) {
4312 pi9->pDevMode = (LPDEVMODEW)buf;
4313 } else
4314 space = FALSE;
4315 *pcbNeeded += size;
4317 else
4319 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size, unicode);
4320 if(space && size <= cbBuf) {
4321 pi9->pDevMode = (LPDEVMODEW)buf;
4322 } else
4323 space = FALSE;
4324 *pcbNeeded += size;
4327 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4328 memset(pi9, 0, sizeof(*pi9));
4330 return space;
4333 /*****************************************************************************
4334 * WINSPOOL_GetPrinter
4336 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
4337 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
4338 * just a collection of pointers to strings.
4340 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4341 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4343 LPCWSTR name;
4344 DWORD size, needed = 0;
4345 LPBYTE ptr = NULL;
4346 HKEY hkeyPrinter, hkeyPrinters;
4347 BOOL ret;
4349 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4351 if (!(name = get_opened_printer_name(hPrinter))) {
4352 SetLastError(ERROR_INVALID_HANDLE);
4353 return FALSE;
4356 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4357 ERROR_SUCCESS) {
4358 ERR("Can't create Printers key\n");
4359 return FALSE;
4361 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
4363 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4364 RegCloseKey(hkeyPrinters);
4365 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4366 return FALSE;
4369 switch(Level) {
4370 case 2:
4372 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4374 size = sizeof(PRINTER_INFO_2W);
4375 if(size <= cbBuf) {
4376 ptr = pPrinter + size;
4377 cbBuf -= size;
4378 memset(pPrinter, 0, size);
4379 } else {
4380 pi2 = NULL;
4381 cbBuf = 0;
4383 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
4384 unicode);
4385 needed += size;
4386 break;
4389 case 4:
4391 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4393 size = sizeof(PRINTER_INFO_4W);
4394 if(size <= cbBuf) {
4395 ptr = pPrinter + size;
4396 cbBuf -= size;
4397 memset(pPrinter, 0, size);
4398 } else {
4399 pi4 = NULL;
4400 cbBuf = 0;
4402 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
4403 unicode);
4404 needed += size;
4405 break;
4409 case 5:
4411 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4413 size = sizeof(PRINTER_INFO_5W);
4414 if(size <= cbBuf) {
4415 ptr = pPrinter + size;
4416 cbBuf -= size;
4417 memset(pPrinter, 0, size);
4418 } else {
4419 pi5 = NULL;
4420 cbBuf = 0;
4423 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
4424 unicode);
4425 needed += size;
4426 break;
4430 case 6:
4432 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4434 size = sizeof(PRINTER_INFO_6);
4435 if (size <= cbBuf) {
4436 /* FIXME: We do not update the status yet */
4437 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
4438 ret = TRUE;
4439 } else {
4440 ret = FALSE;
4443 needed += size;
4444 break;
4447 case 7:
4449 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4451 size = sizeof(PRINTER_INFO_7W);
4452 if (size <= cbBuf) {
4453 ptr = pPrinter + size;
4454 cbBuf -= size;
4455 memset(pPrinter, 0, size);
4456 } else {
4457 pi7 = NULL;
4458 cbBuf = 0;
4461 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed, unicode);
4462 needed += size;
4463 break;
4467 case 9:
4469 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4471 size = sizeof(PRINTER_INFO_9W);
4472 if(size <= cbBuf) {
4473 ptr = pPrinter + size;
4474 cbBuf -= size;
4475 memset(pPrinter, 0, size);
4476 } else {
4477 pi9 = NULL;
4478 cbBuf = 0;
4481 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed, unicode);
4482 needed += size;
4483 break;
4487 default:
4488 FIXME("Unimplemented level %d\n", Level);
4489 SetLastError(ERROR_INVALID_LEVEL);
4490 RegCloseKey(hkeyPrinters);
4491 RegCloseKey(hkeyPrinter);
4492 return FALSE;
4495 RegCloseKey(hkeyPrinter);
4496 RegCloseKey(hkeyPrinters);
4498 TRACE("returning %d needed = %d\n", ret, needed);
4499 if(pcbNeeded) *pcbNeeded = needed;
4500 if(!ret)
4501 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4502 return ret;
4505 /*****************************************************************************
4506 * GetPrinterW [WINSPOOL.@]
4508 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4509 DWORD cbBuf, LPDWORD pcbNeeded)
4511 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4512 TRUE);
4515 /*****************************************************************************
4516 * GetPrinterA [WINSPOOL.@]
4518 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4519 DWORD cbBuf, LPDWORD pcbNeeded)
4521 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4522 FALSE);
4525 /*****************************************************************************
4526 * WINSPOOL_EnumPrinters
4528 * Implementation of EnumPrintersA|W
4530 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
4531 DWORD dwLevel, LPBYTE lpbPrinters,
4532 DWORD cbBuf, LPDWORD lpdwNeeded,
4533 LPDWORD lpdwReturned, BOOL unicode)
4536 HKEY hkeyPrinters, hkeyPrinter;
4537 WCHAR PrinterName[255];
4538 DWORD needed = 0, number = 0;
4539 DWORD used, i, left;
4540 PBYTE pi, buf;
4542 if(lpbPrinters)
4543 memset(lpbPrinters, 0, cbBuf);
4544 if(lpdwReturned)
4545 *lpdwReturned = 0;
4546 if(lpdwNeeded)
4547 *lpdwNeeded = 0;
4549 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4550 if(dwType == PRINTER_ENUM_DEFAULT)
4551 return TRUE;
4553 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4554 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4555 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4556 if (!dwType) {
4557 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4558 *lpdwNeeded = 0;
4559 *lpdwReturned = 0;
4560 return TRUE;
4565 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4566 FIXME("dwType = %08x\n", dwType);
4567 SetLastError(ERROR_INVALID_FLAGS);
4568 return FALSE;
4571 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4572 ERROR_SUCCESS) {
4573 ERR("Can't create Printers key\n");
4574 return FALSE;
4577 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4578 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4579 RegCloseKey(hkeyPrinters);
4580 ERR("Can't query Printers key\n");
4581 return FALSE;
4583 TRACE("Found %d printers\n", number);
4585 switch(dwLevel) {
4586 case 1:
4587 used = number * sizeof(PRINTER_INFO_1W);
4588 break;
4589 case 2:
4590 used = number * sizeof(PRINTER_INFO_2W);
4591 break;
4592 case 4:
4593 used = number * sizeof(PRINTER_INFO_4W);
4594 break;
4595 case 5:
4596 used = number * sizeof(PRINTER_INFO_5W);
4597 break;
4599 default:
4600 SetLastError(ERROR_INVALID_LEVEL);
4601 RegCloseKey(hkeyPrinters);
4602 return FALSE;
4604 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4606 for(i = 0; i < number; i++) {
4607 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4608 ERROR_SUCCESS) {
4609 ERR("Can't enum key number %d\n", i);
4610 RegCloseKey(hkeyPrinters);
4611 return FALSE;
4613 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4614 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4615 ERROR_SUCCESS) {
4616 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4617 RegCloseKey(hkeyPrinters);
4618 return FALSE;
4621 if(cbBuf > used) {
4622 buf = lpbPrinters + used;
4623 left = cbBuf - used;
4624 } else {
4625 buf = NULL;
4626 left = 0;
4629 switch(dwLevel) {
4630 case 1:
4631 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4632 left, &needed, unicode);
4633 used += needed;
4634 if(pi) pi += sizeof(PRINTER_INFO_1W);
4635 break;
4636 case 2:
4637 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4638 left, &needed, unicode);
4639 used += needed;
4640 if(pi) pi += sizeof(PRINTER_INFO_2W);
4641 break;
4642 case 4:
4643 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4644 left, &needed, unicode);
4645 used += needed;
4646 if(pi) pi += sizeof(PRINTER_INFO_4W);
4647 break;
4648 case 5:
4649 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4650 left, &needed, unicode);
4651 used += needed;
4652 if(pi) pi += sizeof(PRINTER_INFO_5W);
4653 break;
4654 default:
4655 ERR("Shouldn't be here!\n");
4656 RegCloseKey(hkeyPrinter);
4657 RegCloseKey(hkeyPrinters);
4658 return FALSE;
4660 RegCloseKey(hkeyPrinter);
4662 RegCloseKey(hkeyPrinters);
4664 if(lpdwNeeded)
4665 *lpdwNeeded = used;
4667 if(used > cbBuf) {
4668 if(lpbPrinters)
4669 memset(lpbPrinters, 0, cbBuf);
4670 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4671 return FALSE;
4673 if(lpdwReturned)
4674 *lpdwReturned = number;
4675 SetLastError(ERROR_SUCCESS);
4676 return TRUE;
4680 /******************************************************************
4681 * EnumPrintersW [WINSPOOL.@]
4683 * Enumerates the available printers, print servers and print
4684 * providers, depending on the specified flags, name and level.
4686 * RETURNS:
4688 * If level is set to 1:
4689 * Returns an array of PRINTER_INFO_1 data structures in the
4690 * lpbPrinters buffer.
4692 * If level is set to 2:
4693 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4694 * Returns an array of PRINTER_INFO_2 data structures in the
4695 * lpbPrinters buffer. Note that according to MSDN also an
4696 * OpenPrinter should be performed on every remote printer.
4698 * If level is set to 4 (officially WinNT only):
4699 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4700 * Fast: Only the registry is queried to retrieve printer names,
4701 * no connection to the driver is made.
4702 * Returns an array of PRINTER_INFO_4 data structures in the
4703 * lpbPrinters buffer.
4705 * If level is set to 5 (officially WinNT4/Win9x only):
4706 * Fast: Only the registry is queried to retrieve printer names,
4707 * no connection to the driver is made.
4708 * Returns an array of PRINTER_INFO_5 data structures in the
4709 * lpbPrinters buffer.
4711 * If level set to 3 or 6+:
4712 * returns zero (failure!)
4714 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4715 * for information.
4717 * BUGS:
4718 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4719 * - Only levels 2, 4 and 5 are implemented at the moment.
4720 * - 16-bit printer drivers are not enumerated.
4721 * - Returned amount of bytes used/needed does not match the real Windoze
4722 * implementation (as in this implementation, all strings are part
4723 * of the buffer, whereas Win32 keeps them somewhere else)
4724 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4726 * NOTE:
4727 * - In a regular Wine installation, no registry settings for printers
4728 * exist, which makes this function return an empty list.
4730 BOOL WINAPI EnumPrintersW(
4731 DWORD dwType, /* [in] Types of print objects to enumerate */
4732 LPWSTR lpszName, /* [in] name of objects to enumerate */
4733 DWORD dwLevel, /* [in] type of printer info structure */
4734 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4735 DWORD cbBuf, /* [in] max size of buffer in bytes */
4736 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4737 LPDWORD lpdwReturned /* [out] number of entries returned */
4740 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4741 lpdwNeeded, lpdwReturned, TRUE);
4744 /******************************************************************
4745 * EnumPrintersA [WINSPOOL.@]
4747 * See EnumPrintersW
4750 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4751 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4753 BOOL ret;
4754 UNICODE_STRING pNameU;
4755 LPWSTR pNameW;
4756 LPBYTE pPrintersW;
4758 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4759 pPrinters, cbBuf, pcbNeeded, pcReturned);
4761 pNameW = asciitounicode(&pNameU, pName);
4763 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4764 MS Office need this */
4765 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4767 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4769 RtlFreeUnicodeString(&pNameU);
4770 if (ret) {
4771 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4773 HeapFree(GetProcessHeap(), 0, pPrintersW);
4774 return ret;
4777 /*****************************************************************************
4778 * WINSPOOL_GetDriverInfoFromReg [internal]
4780 * Enters the information from the registry into the DRIVER_INFO struct
4782 * RETURNS
4783 * zero if the printer driver does not exist in the registry
4784 * (only if Level > 1) otherwise nonzero
4786 static BOOL WINSPOOL_GetDriverInfoFromReg(
4787 HKEY hkeyDrivers,
4788 LPWSTR DriverName,
4789 const printenv_t * env,
4790 DWORD Level,
4791 LPBYTE ptr, /* DRIVER_INFO */
4792 LPBYTE pDriverStrings, /* strings buffer */
4793 DWORD cbBuf, /* size of string buffer */
4794 LPDWORD pcbNeeded, /* space needed for str. */
4795 BOOL unicode) /* type of strings */
4797 DWORD size, tmp;
4798 HKEY hkeyDriver;
4799 WCHAR driverdir[MAX_PATH];
4800 DWORD dirlen;
4801 LPBYTE strPtr = pDriverStrings;
4802 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4804 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers,
4805 debugstr_w(DriverName), env,
4806 Level, di, pDriverStrings, cbBuf, unicode);
4808 if (di) ZeroMemory(di, di_sizeof[Level]);
4810 if (unicode) {
4811 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4812 if (*pcbNeeded <= cbBuf)
4813 strcpyW((LPWSTR)strPtr, DriverName);
4815 else
4817 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL, NULL);
4818 if (*pcbNeeded <= cbBuf)
4819 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4822 /* pName for level 1 has a different offset! */
4823 if (Level == 1) {
4824 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4825 return TRUE;
4828 /* .cVersion and .pName for level > 1 */
4829 if (di) {
4830 di->cVersion = env->driverversion;
4831 di->pName = (LPWSTR) strPtr;
4832 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4835 /* Reserve Space for the largest subdir and a Backslash*/
4836 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4837 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4838 /* Should never Fail */
4839 return FALSE;
4841 lstrcatW(driverdir, env->versionsubdir);
4842 lstrcatW(driverdir, backslashW);
4844 /* dirlen must not include the terminating zero */
4845 dirlen = (unicode) ? lstrlenW(driverdir) * sizeof(WCHAR) :
4846 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, NULL, 0, NULL, NULL) -1;
4848 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4849 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4850 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4851 return FALSE;
4854 /* pEnvironment */
4855 if (unicode)
4856 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4857 else
4858 size = WideCharToMultiByte(CP_ACP, 0, env->envname, -1, NULL, 0, NULL, NULL);
4860 *pcbNeeded += size;
4861 if (*pcbNeeded <= cbBuf) {
4862 if (unicode) {
4863 lstrcpyW((LPWSTR)strPtr, env->envname);
4865 else
4867 WideCharToMultiByte(CP_ACP, 0, env->envname, -1, (LPSTR)strPtr, size, NULL, NULL);
4869 if (di) di->pEnvironment = (LPWSTR)strPtr;
4870 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4873 /* .pDriverPath is the Graphics rendering engine.
4874 The full Path is required to avoid a crash in some apps */
4875 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size, unicode)) {
4876 *pcbNeeded += size;
4877 if (*pcbNeeded <= cbBuf)
4878 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp, unicode);
4880 if (di) di->pDriverPath = (LPWSTR)strPtr;
4881 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4884 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4885 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size, unicode)) {
4886 *pcbNeeded += size;
4887 if (*pcbNeeded <= cbBuf)
4888 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size, unicode);
4890 if (di) di->pDataFile = (LPWSTR)strPtr;
4891 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4894 /* .pConfigFile is the Driver user Interface */
4895 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size, unicode)) {
4896 *pcbNeeded += size;
4897 if (*pcbNeeded <= cbBuf)
4898 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size, unicode);
4900 if (di) di->pConfigFile = (LPWSTR)strPtr;
4901 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4904 if (Level == 2 ) {
4905 RegCloseKey(hkeyDriver);
4906 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4907 return TRUE;
4910 if (Level == 5 ) {
4911 RegCloseKey(hkeyDriver);
4912 FIXME("level 5: incomplete\n");
4913 return TRUE;
4916 /* .pHelpFile */
4917 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size, unicode)) {
4918 *pcbNeeded += size;
4919 if (*pcbNeeded <= cbBuf)
4920 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size, unicode);
4922 if (di) di->pHelpFile = (LPWSTR)strPtr;
4923 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4926 /* .pDependentFiles */
4927 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size, unicode)) {
4928 *pcbNeeded += size;
4929 if (*pcbNeeded <= cbBuf)
4930 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size, unicode);
4932 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4933 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4935 else if (GetVersion() & 0x80000000) {
4936 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4937 size = 2 * ((unicode) ? sizeof(WCHAR) : 1);
4938 *pcbNeeded += size;
4939 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4941 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4942 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4945 /* .pMonitorName is the optional Language Monitor */
4946 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size, unicode)) {
4947 *pcbNeeded += size;
4948 if (*pcbNeeded <= cbBuf)
4949 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size, unicode);
4951 if (di) di->pMonitorName = (LPWSTR)strPtr;
4952 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4955 /* .pDefaultDataType */
4956 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size, unicode)) {
4957 *pcbNeeded += size;
4958 if(*pcbNeeded <= cbBuf)
4959 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size, unicode);
4961 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4962 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4965 if (Level == 3 ) {
4966 RegCloseKey(hkeyDriver);
4967 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4968 return TRUE;
4971 /* .pszzPreviousNames */
4972 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size, unicode)) {
4973 *pcbNeeded += size;
4974 if(*pcbNeeded <= cbBuf)
4975 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size, unicode);
4977 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4978 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4981 if (Level == 4 ) {
4982 RegCloseKey(hkeyDriver);
4983 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4984 return TRUE;
4987 /* support is missing, but not important enough for a FIXME */
4988 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4990 /* .pszMfgName */
4991 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size, unicode)) {
4992 *pcbNeeded += size;
4993 if(*pcbNeeded <= cbBuf)
4994 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size, unicode);
4996 if (di) di->pszMfgName = (LPWSTR)strPtr;
4997 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5000 /* .pszOEMUrl */
5001 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size, unicode)) {
5002 *pcbNeeded += size;
5003 if(*pcbNeeded <= cbBuf)
5004 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size, unicode);
5006 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
5007 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5010 /* .pszHardwareID */
5011 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size, unicode)) {
5012 *pcbNeeded += size;
5013 if(*pcbNeeded <= cbBuf)
5014 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size, unicode);
5016 if (di) di->pszHardwareID = (LPWSTR)strPtr;
5017 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5020 /* .pszProvider */
5021 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size, unicode)) {
5022 *pcbNeeded += size;
5023 if(*pcbNeeded <= cbBuf)
5024 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size, unicode);
5026 if (di) di->pszProvider = (LPWSTR)strPtr;
5027 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5030 if (Level == 6 ) {
5031 RegCloseKey(hkeyDriver);
5032 return TRUE;
5035 /* support is missing, but not important enough for a FIXME */
5036 TRACE("level 8: incomplete\n");
5038 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5039 RegCloseKey(hkeyDriver);
5040 return TRUE;
5043 /*****************************************************************************
5044 * WINSPOOL_GetPrinterDriver
5046 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
5047 DWORD Level, LPBYTE pDriverInfo,
5048 DWORD cbBuf, LPDWORD pcbNeeded,
5049 BOOL unicode)
5051 LPCWSTR name;
5052 WCHAR DriverName[100];
5053 DWORD ret, type, size, needed = 0;
5054 LPBYTE ptr = NULL;
5055 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
5056 const printenv_t * env;
5058 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
5059 Level,pDriverInfo,cbBuf, pcbNeeded);
5062 if (!(name = get_opened_printer_name(hPrinter))) {
5063 SetLastError(ERROR_INVALID_HANDLE);
5064 return FALSE;
5067 if (Level < 1 || Level == 7 || Level > 8) {
5068 SetLastError(ERROR_INVALID_LEVEL);
5069 return FALSE;
5072 env = validate_envW(pEnvironment);
5073 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5075 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
5076 ERROR_SUCCESS) {
5077 ERR("Can't create Printers key\n");
5078 return FALSE;
5080 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
5081 != ERROR_SUCCESS) {
5082 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
5083 RegCloseKey(hkeyPrinters);
5084 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
5085 return FALSE;
5087 size = sizeof(DriverName);
5088 DriverName[0] = 0;
5089 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
5090 (LPBYTE)DriverName, &size);
5091 RegCloseKey(hkeyPrinter);
5092 RegCloseKey(hkeyPrinters);
5093 if(ret != ERROR_SUCCESS) {
5094 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
5095 return FALSE;
5098 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
5099 if(!hkeyDrivers) {
5100 ERR("Can't create Drivers key\n");
5101 return FALSE;
5104 size = di_sizeof[Level];
5105 if ((size <= cbBuf) && pDriverInfo)
5106 ptr = pDriverInfo + size;
5108 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
5109 env, Level, pDriverInfo, ptr,
5110 (cbBuf < size) ? 0 : cbBuf - size,
5111 &needed, unicode)) {
5112 RegCloseKey(hkeyDrivers);
5113 return FALSE;
5116 RegCloseKey(hkeyDrivers);
5118 if(pcbNeeded) *pcbNeeded = size + needed;
5119 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
5120 if(cbBuf >= needed) return TRUE;
5121 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5122 return FALSE;
5125 /*****************************************************************************
5126 * GetPrinterDriverA [WINSPOOL.@]
5128 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
5129 DWORD Level, LPBYTE pDriverInfo,
5130 DWORD cbBuf, LPDWORD pcbNeeded)
5132 BOOL ret;
5133 UNICODE_STRING pEnvW;
5134 PWSTR pwstrEnvW;
5136 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
5137 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
5138 cbBuf, pcbNeeded, FALSE);
5139 RtlFreeUnicodeString(&pEnvW);
5140 return ret;
5142 /*****************************************************************************
5143 * GetPrinterDriverW [WINSPOOL.@]
5145 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
5146 DWORD Level, LPBYTE pDriverInfo,
5147 DWORD cbBuf, LPDWORD pcbNeeded)
5149 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
5150 pDriverInfo, cbBuf, pcbNeeded, TRUE);
5153 /*****************************************************************************
5154 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5156 * Return the PATH for the Printer-Drivers (UNICODE)
5158 * PARAMS
5159 * pName [I] Servername (NT only) or NULL (local Computer)
5160 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5161 * Level [I] Structure-Level (must be 1)
5162 * pDriverDirectory [O] PTR to Buffer that receives the Result
5163 * cbBuf [I] Size of Buffer at pDriverDirectory
5164 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5165 * required for pDriverDirectory
5167 * RETURNS
5168 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5169 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5170 * if cbBuf is too small
5172 * Native Values returned in pDriverDirectory on Success:
5173 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5174 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5175 *| win9x(Windows 4.0): "%winsysdir%"
5177 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5179 * FIXME
5180 *- Only NULL or "" is supported for pName
5183 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
5184 DWORD Level, LPBYTE pDriverDirectory,
5185 DWORD cbBuf, LPDWORD pcbNeeded)
5187 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
5188 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5190 if ((backend == NULL) && !load_backend()) return FALSE;
5192 if (Level != 1) {
5193 /* (Level != 1) is ignored in win9x */
5194 SetLastError(ERROR_INVALID_LEVEL);
5195 return FALSE;
5197 if (pcbNeeded == NULL) {
5198 /* (pcbNeeded == NULL) is ignored in win9x */
5199 SetLastError(RPC_X_NULL_REF_POINTER);
5200 return FALSE;
5203 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5204 pDriverDirectory, cbBuf, pcbNeeded);
5209 /*****************************************************************************
5210 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5212 * Return the PATH for the Printer-Drivers (ANSI)
5214 * See GetPrinterDriverDirectoryW.
5216 * NOTES
5217 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5220 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
5221 DWORD Level, LPBYTE pDriverDirectory,
5222 DWORD cbBuf, LPDWORD pcbNeeded)
5224 UNICODE_STRING nameW, environmentW;
5225 BOOL ret;
5226 DWORD pcbNeededW;
5227 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5228 WCHAR *driverDirectoryW = NULL;
5230 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
5231 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5233 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5235 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5236 else nameW.Buffer = NULL;
5237 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5238 else environmentW.Buffer = NULL;
5240 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5241 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5242 if (ret) {
5243 DWORD needed;
5244 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
5245 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
5246 if(pcbNeeded)
5247 *pcbNeeded = needed;
5248 ret = (needed <= cbBuf) ? TRUE : FALSE;
5249 } else
5250 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
5252 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
5254 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
5255 RtlFreeUnicodeString(&environmentW);
5256 RtlFreeUnicodeString(&nameW);
5258 return ret;
5261 /*****************************************************************************
5262 * AddPrinterDriverA [WINSPOOL.@]
5264 * See AddPrinterDriverW.
5267 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5269 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5270 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5273 /******************************************************************************
5274 * AddPrinterDriverW (WINSPOOL.@)
5276 * Install a Printer Driver
5278 * PARAMS
5279 * pName [I] Servername or NULL (local Computer)
5280 * level [I] Level for the supplied DRIVER_INFO_*W struct
5281 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5283 * RESULTS
5284 * Success: TRUE
5285 * Failure: FALSE
5288 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5290 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5291 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5294 /*****************************************************************************
5295 * AddPrintProcessorA [WINSPOOL.@]
5297 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5298 LPSTR pPrintProcessorName)
5300 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5301 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5302 return FALSE;
5305 /*****************************************************************************
5306 * AddPrintProcessorW [WINSPOOL.@]
5308 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5309 LPWSTR pPrintProcessorName)
5311 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5312 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5313 return FALSE;
5316 /*****************************************************************************
5317 * AddPrintProvidorA [WINSPOOL.@]
5319 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5321 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5322 return FALSE;
5325 /*****************************************************************************
5326 * AddPrintProvidorW [WINSPOOL.@]
5328 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5330 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5331 return FALSE;
5334 /*****************************************************************************
5335 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5337 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5338 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5340 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5341 pDevModeOutput, pDevModeInput);
5342 return 0;
5345 /*****************************************************************************
5346 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5348 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5349 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5351 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5352 pDevModeOutput, pDevModeInput);
5353 return 0;
5356 /*****************************************************************************
5357 * PrinterProperties [WINSPOOL.@]
5359 * Displays a dialog to set the properties of the printer.
5361 * RETURNS
5362 * nonzero on success or zero on failure
5364 * BUGS
5365 * implemented as stub only
5367 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5368 HANDLE hPrinter /* [in] handle to printer object */
5370 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5371 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5372 return FALSE;
5375 /*****************************************************************************
5376 * EnumJobsA [WINSPOOL.@]
5379 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5380 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5381 LPDWORD pcReturned)
5383 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5384 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5386 if(pcbNeeded) *pcbNeeded = 0;
5387 if(pcReturned) *pcReturned = 0;
5388 return FALSE;
5392 /*****************************************************************************
5393 * EnumJobsW [WINSPOOL.@]
5396 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5397 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5398 LPDWORD pcReturned)
5400 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5401 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5403 if(pcbNeeded) *pcbNeeded = 0;
5404 if(pcReturned) *pcReturned = 0;
5405 return FALSE;
5408 /*****************************************************************************
5409 * WINSPOOL_EnumPrinterDrivers [internal]
5411 * Delivers information about all printer drivers installed on the
5412 * localhost or a given server
5414 * RETURNS
5415 * nonzero on success or zero on failure. If the buffer for the returned
5416 * information is too small the function will return an error
5418 * BUGS
5419 * - only implemented for localhost, foreign hosts will return an error
5421 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5422 DWORD Level, LPBYTE pDriverInfo,
5423 DWORD cbBuf, LPDWORD pcbNeeded,
5424 LPDWORD pcReturned, BOOL unicode)
5426 { HKEY hkeyDrivers;
5427 DWORD i, needed, number = 0, size = 0;
5428 WCHAR DriverNameW[255];
5429 PBYTE ptr;
5430 const printenv_t * env;
5432 TRACE("%s,%s,%d,%p,%d,%d\n",
5433 debugstr_w(pName), debugstr_w(pEnvironment),
5434 Level, pDriverInfo, cbBuf, unicode);
5436 /* check for local drivers */
5437 if((pName) && (pName[0])) {
5438 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5439 SetLastError(ERROR_ACCESS_DENIED);
5440 return FALSE;
5443 env = validate_envW(pEnvironment);
5444 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5446 /* check input parameter */
5447 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5448 SetLastError(ERROR_INVALID_LEVEL);
5449 return FALSE;
5452 if ((pcbNeeded == NULL) || (pcReturned == NULL)) {
5453 SetLastError(RPC_X_NULL_REF_POINTER);
5454 return FALSE;
5457 /* initialize return values */
5458 if(pDriverInfo)
5459 memset( pDriverInfo, 0, cbBuf);
5460 *pcbNeeded = 0;
5461 *pcReturned = 0;
5463 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
5464 if(!hkeyDrivers) {
5465 ERR("Can't open Drivers key\n");
5466 return FALSE;
5469 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
5470 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5471 RegCloseKey(hkeyDrivers);
5472 ERR("Can't query Drivers key\n");
5473 return FALSE;
5475 TRACE("Found %d Drivers\n", number);
5477 /* get size of single struct
5478 * unicode and ascii structure have the same size
5480 size = di_sizeof[Level];
5482 /* calculate required buffer size */
5483 *pcbNeeded = size * number;
5485 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
5486 i < number;
5487 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
5488 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5489 != ERROR_SUCCESS) {
5490 ERR("Can't enum key number %d\n", i);
5491 RegCloseKey(hkeyDrivers);
5492 return FALSE;
5494 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5495 env, Level, ptr,
5496 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
5497 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5498 &needed, unicode)) {
5499 RegCloseKey(hkeyDrivers);
5500 return FALSE;
5502 (*pcbNeeded) += needed;
5505 RegCloseKey(hkeyDrivers);
5507 if(cbBuf < *pcbNeeded){
5508 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5509 return FALSE;
5512 *pcReturned = number;
5513 return TRUE;
5516 /*****************************************************************************
5517 * EnumPrinterDriversW [WINSPOOL.@]
5519 * see function EnumPrinterDrivers for RETURNS, BUGS
5521 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5522 LPBYTE pDriverInfo, DWORD cbBuf,
5523 LPDWORD pcbNeeded, LPDWORD pcReturned)
5525 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5526 cbBuf, pcbNeeded, pcReturned, TRUE);
5529 /*****************************************************************************
5530 * EnumPrinterDriversA [WINSPOOL.@]
5532 * see function EnumPrinterDrivers for RETURNS, BUGS
5534 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5535 LPBYTE pDriverInfo, DWORD cbBuf,
5536 LPDWORD pcbNeeded, LPDWORD pcReturned)
5537 { BOOL ret;
5538 UNICODE_STRING pNameW, pEnvironmentW;
5539 PWSTR pwstrNameW, pwstrEnvironmentW;
5541 pwstrNameW = asciitounicode(&pNameW, pName);
5542 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5544 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5545 Level, pDriverInfo, cbBuf, pcbNeeded,
5546 pcReturned, FALSE);
5547 RtlFreeUnicodeString(&pNameW);
5548 RtlFreeUnicodeString(&pEnvironmentW);
5550 return ret;
5553 /******************************************************************************
5554 * EnumPortsA (WINSPOOL.@)
5556 * See EnumPortsW.
5559 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5560 LPDWORD pcbNeeded, LPDWORD pcReturned)
5562 BOOL res;
5563 LPBYTE bufferW = NULL;
5564 LPWSTR nameW = NULL;
5565 DWORD needed = 0;
5566 DWORD numentries = 0;
5567 INT len;
5569 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5570 cbBuf, pcbNeeded, pcReturned);
5572 /* convert servername to unicode */
5573 if (pName) {
5574 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5575 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5576 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5578 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5579 needed = cbBuf * sizeof(WCHAR);
5580 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5581 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5583 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5584 if (pcbNeeded) needed = *pcbNeeded;
5585 /* HeapReAlloc return NULL, when bufferW was NULL */
5586 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5587 HeapAlloc(GetProcessHeap(), 0, needed);
5589 /* Try again with the large Buffer */
5590 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5592 needed = pcbNeeded ? *pcbNeeded : 0;
5593 numentries = pcReturned ? *pcReturned : 0;
5596 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5597 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5599 if (res) {
5600 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5601 DWORD entrysize = 0;
5602 DWORD index;
5603 LPSTR ptr;
5604 LPPORT_INFO_2W pi2w;
5605 LPPORT_INFO_2A pi2a;
5607 needed = 0;
5608 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5610 /* First pass: calculate the size for all Entries */
5611 pi2w = (LPPORT_INFO_2W) bufferW;
5612 pi2a = (LPPORT_INFO_2A) pPorts;
5613 index = 0;
5614 while (index < numentries) {
5615 index++;
5616 needed += entrysize; /* PORT_INFO_?A */
5617 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5619 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5620 NULL, 0, NULL, NULL);
5621 if (Level > 1) {
5622 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5623 NULL, 0, NULL, NULL);
5624 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5625 NULL, 0, NULL, NULL);
5627 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5628 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5629 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5632 /* check for errors and quit on failure */
5633 if (cbBuf < needed) {
5634 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5635 res = FALSE;
5636 goto cleanup;
5638 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5639 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5640 cbBuf -= len ; /* free Bytes in the user-Buffer */
5641 pi2w = (LPPORT_INFO_2W) bufferW;
5642 pi2a = (LPPORT_INFO_2A) pPorts;
5643 index = 0;
5644 /* Second Pass: Fill the User Buffer (if we have one) */
5645 while ((index < numentries) && pPorts) {
5646 index++;
5647 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5648 pi2a->pPortName = ptr;
5649 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5650 ptr, cbBuf , NULL, NULL);
5651 ptr += len;
5652 cbBuf -= len;
5653 if (Level > 1) {
5654 pi2a->pMonitorName = ptr;
5655 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5656 ptr, cbBuf, NULL, NULL);
5657 ptr += len;
5658 cbBuf -= len;
5660 pi2a->pDescription = ptr;
5661 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5662 ptr, cbBuf, NULL, NULL);
5663 ptr += len;
5664 cbBuf -= len;
5666 pi2a->fPortType = pi2w->fPortType;
5667 pi2a->Reserved = 0; /* documented: "must be zero" */
5670 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5671 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5672 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5676 cleanup:
5677 if (pcbNeeded) *pcbNeeded = needed;
5678 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5680 HeapFree(GetProcessHeap(), 0, nameW);
5681 HeapFree(GetProcessHeap(), 0, bufferW);
5683 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5684 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5686 return (res);
5690 /******************************************************************************
5691 * EnumPortsW (WINSPOOL.@)
5693 * Enumerate available Ports
5695 * PARAMS
5696 * name [I] Servername or NULL (local Computer)
5697 * level [I] Structure-Level (1 or 2)
5698 * buffer [O] PTR to Buffer that receives the Result
5699 * bufsize [I] Size of Buffer at buffer
5700 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5701 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5703 * RETURNS
5704 * Success: TRUE
5705 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5709 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5711 DWORD needed = 0;
5712 DWORD numentries = 0;
5713 BOOL res = FALSE;
5715 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5716 cbBuf, pcbNeeded, pcReturned);
5718 if (pName && (pName[0])) {
5719 FIXME("not implemented for Server %s\n", debugstr_w(pName));
5720 SetLastError(ERROR_ACCESS_DENIED);
5721 goto emP_cleanup;
5724 /* Level is not checked in win9x */
5725 if (!Level || (Level > 2)) {
5726 WARN("level (%d) is ignored in win9x\n", Level);
5727 SetLastError(ERROR_INVALID_LEVEL);
5728 goto emP_cleanup;
5730 if (!pcbNeeded) {
5731 SetLastError(RPC_X_NULL_REF_POINTER);
5732 goto emP_cleanup;
5735 EnterCriticalSection(&monitor_handles_cs);
5736 monitor_loadall();
5738 /* Scan all local Ports */
5739 numentries = 0;
5740 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
5742 /* we calculated the needed buffersize. now do the error-checks */
5743 if (cbBuf < needed) {
5744 monitor_unloadall();
5745 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5746 goto emP_cleanup_cs;
5748 else if (!pPorts || !pcReturned) {
5749 monitor_unloadall();
5750 SetLastError(RPC_X_NULL_REF_POINTER);
5751 goto emP_cleanup_cs;
5754 /* Fill the Buffer */
5755 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
5756 res = TRUE;
5757 monitor_unloadall();
5759 emP_cleanup_cs:
5760 LeaveCriticalSection(&monitor_handles_cs);
5762 emP_cleanup:
5763 if (pcbNeeded) *pcbNeeded = needed;
5764 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5766 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5767 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5769 return (res);
5772 /******************************************************************************
5773 * GetDefaultPrinterW (WINSPOOL.@)
5775 * FIXME
5776 * This function must read the value from data 'device' of key
5777 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5779 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5781 BOOL retval = TRUE;
5782 DWORD insize, len;
5783 WCHAR *buffer, *ptr;
5785 if (!namesize)
5787 SetLastError(ERROR_INVALID_PARAMETER);
5788 return FALSE;
5791 /* make the buffer big enough for the stuff from the profile/registry,
5792 * the content must fit into the local buffer to compute the correct
5793 * size even if the extern buffer is too small or not given.
5794 * (20 for ,driver,port) */
5795 insize = *namesize;
5796 len = max(100, (insize + 20));
5797 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5799 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5801 SetLastError (ERROR_FILE_NOT_FOUND);
5802 retval = FALSE;
5803 goto end;
5805 TRACE("%s\n", debugstr_w(buffer));
5807 if ((ptr = strchrW(buffer, ',')) == NULL)
5809 SetLastError(ERROR_INVALID_NAME);
5810 retval = FALSE;
5811 goto end;
5814 *ptr = 0;
5815 *namesize = strlenW(buffer) + 1;
5816 if(!name || (*namesize > insize))
5818 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5819 retval = FALSE;
5820 goto end;
5822 strcpyW(name, buffer);
5824 end:
5825 HeapFree( GetProcessHeap(), 0, buffer);
5826 return retval;
5830 /******************************************************************************
5831 * GetDefaultPrinterA (WINSPOOL.@)
5833 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5835 BOOL retval = TRUE;
5836 DWORD insize = 0;
5837 WCHAR *bufferW = NULL;
5839 if (!namesize)
5841 SetLastError(ERROR_INVALID_PARAMETER);
5842 return FALSE;
5845 if(name && *namesize) {
5846 insize = *namesize;
5847 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5850 if(!GetDefaultPrinterW( bufferW, namesize)) {
5851 retval = FALSE;
5852 goto end;
5855 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5856 NULL, NULL);
5857 if (!*namesize)
5859 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5860 retval = FALSE;
5862 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5864 end:
5865 HeapFree( GetProcessHeap(), 0, bufferW);
5866 return retval;
5870 /******************************************************************************
5871 * SetDefaultPrinterW (WINSPOOL.204)
5873 * Set the Name of the Default Printer
5875 * PARAMS
5876 * pszPrinter [I] Name of the Printer or NULL
5878 * RETURNS
5879 * Success: True
5880 * Failure: FALSE
5882 * NOTES
5883 * When the Parameter is NULL or points to an Empty String and
5884 * a Default Printer was already present, then this Function changes nothing.
5885 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5886 * the First enumerated local Printer is used.
5889 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5892 TRACE("(%s)\n", debugstr_w(pszPrinter));
5894 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5895 return FALSE;
5898 /******************************************************************************
5899 * SetDefaultPrinterA (WINSPOOL.202)
5901 * See SetDefaultPrinterW.
5904 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5907 TRACE("(%s)\n", debugstr_a(pszPrinter));
5909 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5910 return FALSE;
5914 /******************************************************************************
5915 * SetPrinterDataExA (WINSPOOL.@)
5917 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5918 LPCSTR pValueName, DWORD Type,
5919 LPBYTE pData, DWORD cbData)
5921 HKEY hkeyPrinter, hkeySubkey;
5922 DWORD ret;
5924 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5925 debugstr_a(pValueName), Type, pData, cbData);
5927 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5928 != ERROR_SUCCESS)
5929 return ret;
5931 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5932 != ERROR_SUCCESS) {
5933 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5934 RegCloseKey(hkeyPrinter);
5935 return ret;
5937 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5938 RegCloseKey(hkeySubkey);
5939 RegCloseKey(hkeyPrinter);
5940 return ret;
5943 /******************************************************************************
5944 * SetPrinterDataExW (WINSPOOL.@)
5946 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5947 LPCWSTR pValueName, DWORD Type,
5948 LPBYTE pData, DWORD cbData)
5950 HKEY hkeyPrinter, hkeySubkey;
5951 DWORD ret;
5953 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5954 debugstr_w(pValueName), Type, pData, cbData);
5956 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5957 != ERROR_SUCCESS)
5958 return ret;
5960 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5961 != ERROR_SUCCESS) {
5962 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5963 RegCloseKey(hkeyPrinter);
5964 return ret;
5966 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5967 RegCloseKey(hkeySubkey);
5968 RegCloseKey(hkeyPrinter);
5969 return ret;
5972 /******************************************************************************
5973 * SetPrinterDataA (WINSPOOL.@)
5975 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5976 LPBYTE pData, DWORD cbData)
5978 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5979 pData, cbData);
5982 /******************************************************************************
5983 * SetPrinterDataW (WINSPOOL.@)
5985 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5986 LPBYTE pData, DWORD cbData)
5988 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5989 pData, cbData);
5992 /******************************************************************************
5993 * GetPrinterDataExA (WINSPOOL.@)
5995 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5996 LPCSTR pValueName, LPDWORD pType,
5997 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5999 HKEY hkeyPrinter, hkeySubkey;
6000 DWORD ret;
6002 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
6003 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
6004 pcbNeeded);
6006 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6007 != ERROR_SUCCESS)
6008 return ret;
6010 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
6011 != ERROR_SUCCESS) {
6012 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
6013 RegCloseKey(hkeyPrinter);
6014 return ret;
6016 *pcbNeeded = nSize;
6017 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
6018 RegCloseKey(hkeySubkey);
6019 RegCloseKey(hkeyPrinter);
6020 return ret;
6023 /******************************************************************************
6024 * GetPrinterDataExW (WINSPOOL.@)
6026 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6027 LPCWSTR pValueName, LPDWORD pType,
6028 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6030 HKEY hkeyPrinter, hkeySubkey;
6031 DWORD ret;
6033 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
6034 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
6035 pcbNeeded);
6037 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6038 != ERROR_SUCCESS)
6039 return ret;
6041 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
6042 != ERROR_SUCCESS) {
6043 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
6044 RegCloseKey(hkeyPrinter);
6045 return ret;
6047 *pcbNeeded = nSize;
6048 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
6049 RegCloseKey(hkeySubkey);
6050 RegCloseKey(hkeyPrinter);
6051 return ret;
6054 /******************************************************************************
6055 * GetPrinterDataA (WINSPOOL.@)
6057 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
6058 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6060 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
6061 pData, nSize, pcbNeeded);
6064 /******************************************************************************
6065 * GetPrinterDataW (WINSPOOL.@)
6067 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
6068 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6070 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
6071 pData, nSize, pcbNeeded);
6074 /*******************************************************************************
6075 * EnumPrinterDataExW [WINSPOOL.@]
6077 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6078 LPBYTE pEnumValues, DWORD cbEnumValues,
6079 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6081 HKEY hkPrinter, hkSubKey;
6082 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
6083 cbValueNameLen, cbMaxValueLen, cbValueLen,
6084 cbBufSize, dwType;
6085 LPWSTR lpValueName;
6086 HANDLE hHeap;
6087 PBYTE lpValue;
6088 PPRINTER_ENUM_VALUESW ppev;
6090 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
6092 if (pKeyName == NULL || *pKeyName == 0)
6093 return ERROR_INVALID_PARAMETER;
6095 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
6096 if (ret != ERROR_SUCCESS)
6098 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6099 hPrinter, ret);
6100 return ret;
6103 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
6104 if (ret != ERROR_SUCCESS)
6106 r = RegCloseKey (hkPrinter);
6107 if (r != ERROR_SUCCESS)
6108 WARN ("RegCloseKey returned %i\n", r);
6109 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
6110 debugstr_w (pKeyName), ret);
6111 return ret;
6114 ret = RegCloseKey (hkPrinter);
6115 if (ret != ERROR_SUCCESS)
6117 ERR ("RegCloseKey returned %i\n", ret);
6118 r = RegCloseKey (hkSubKey);
6119 if (r != ERROR_SUCCESS)
6120 WARN ("RegCloseKey returned %i\n", r);
6121 return ret;
6124 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
6125 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
6126 if (ret != ERROR_SUCCESS)
6128 r = RegCloseKey (hkSubKey);
6129 if (r != ERROR_SUCCESS)
6130 WARN ("RegCloseKey returned %i\n", r);
6131 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
6132 return ret;
6135 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6136 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
6138 if (cValues == 0) /* empty key */
6140 r = RegCloseKey (hkSubKey);
6141 if (r != ERROR_SUCCESS)
6142 WARN ("RegCloseKey returned %i\n", r);
6143 *pcbEnumValues = *pnEnumValues = 0;
6144 return ERROR_SUCCESS;
6147 ++cbMaxValueNameLen; /* allow for trailing '\0' */
6149 hHeap = GetProcessHeap ();
6150 if (hHeap == NULL)
6152 ERR ("GetProcessHeap failed\n");
6153 r = RegCloseKey (hkSubKey);
6154 if (r != ERROR_SUCCESS)
6155 WARN ("RegCloseKey returned %i\n", r);
6156 return ERROR_OUTOFMEMORY;
6159 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
6160 if (lpValueName == NULL)
6162 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
6163 r = RegCloseKey (hkSubKey);
6164 if (r != ERROR_SUCCESS)
6165 WARN ("RegCloseKey returned %i\n", r);
6166 return ERROR_OUTOFMEMORY;
6169 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
6170 if (lpValue == NULL)
6172 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
6173 if (HeapFree (hHeap, 0, lpValueName) == 0)
6174 WARN ("HeapFree failed with code %i\n", GetLastError ());
6175 r = RegCloseKey (hkSubKey);
6176 if (r != ERROR_SUCCESS)
6177 WARN ("RegCloseKey returned %i\n", r);
6178 return ERROR_OUTOFMEMORY;
6181 TRACE ("pass 1: calculating buffer required for all names and values\n");
6183 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
6185 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
6187 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6189 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6190 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6191 NULL, NULL, lpValue, &cbValueLen);
6192 if (ret != ERROR_SUCCESS)
6194 if (HeapFree (hHeap, 0, lpValue) == 0)
6195 WARN ("HeapFree failed with code %i\n", GetLastError ());
6196 if (HeapFree (hHeap, 0, lpValueName) == 0)
6197 WARN ("HeapFree failed with code %i\n", GetLastError ());
6198 r = RegCloseKey (hkSubKey);
6199 if (r != ERROR_SUCCESS)
6200 WARN ("RegCloseKey returned %i\n", r);
6201 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6202 return ret;
6205 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6206 debugstr_w (lpValueName), dwIndex,
6207 cbValueNameLen + 1, cbValueLen);
6209 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6210 cbBufSize += cbValueLen;
6213 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
6215 *pcbEnumValues = cbBufSize;
6216 *pnEnumValues = cValues;
6218 if (cbEnumValues < cbBufSize) /* buffer too small */
6220 if (HeapFree (hHeap, 0, lpValue) == 0)
6221 WARN ("HeapFree failed with code %i\n", GetLastError ());
6222 if (HeapFree (hHeap, 0, lpValueName) == 0)
6223 WARN ("HeapFree failed with code %i\n", GetLastError ());
6224 r = RegCloseKey (hkSubKey);
6225 if (r != ERROR_SUCCESS)
6226 WARN ("RegCloseKey returned %i\n", r);
6227 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
6228 return ERROR_MORE_DATA;
6231 TRACE ("pass 2: copying all names and values to buffer\n");
6233 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6234 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6236 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6238 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6239 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6240 NULL, &dwType, lpValue, &cbValueLen);
6241 if (ret != ERROR_SUCCESS)
6243 if (HeapFree (hHeap, 0, lpValue) == 0)
6244 WARN ("HeapFree failed with code %i\n", GetLastError ());
6245 if (HeapFree (hHeap, 0, lpValueName) == 0)
6246 WARN ("HeapFree failed with code %i\n", GetLastError ());
6247 r = RegCloseKey (hkSubKey);
6248 if (r != ERROR_SUCCESS)
6249 WARN ("RegCloseKey returned %i\n", r);
6250 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6251 return ret;
6254 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6255 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6256 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6257 pEnumValues += cbValueNameLen;
6259 /* return # of *bytes* (including trailing \0), not # of chars */
6260 ppev[dwIndex].cbValueName = cbValueNameLen;
6262 ppev[dwIndex].dwType = dwType;
6264 memcpy (pEnumValues, lpValue, cbValueLen);
6265 ppev[dwIndex].pData = pEnumValues;
6266 pEnumValues += cbValueLen;
6268 ppev[dwIndex].cbData = cbValueLen;
6270 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6271 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6274 if (HeapFree (hHeap, 0, lpValue) == 0)
6276 ret = GetLastError ();
6277 ERR ("HeapFree failed with code %i\n", ret);
6278 if (HeapFree (hHeap, 0, lpValueName) == 0)
6279 WARN ("HeapFree failed with code %i\n", GetLastError ());
6280 r = RegCloseKey (hkSubKey);
6281 if (r != ERROR_SUCCESS)
6282 WARN ("RegCloseKey returned %i\n", r);
6283 return ret;
6286 if (HeapFree (hHeap, 0, lpValueName) == 0)
6288 ret = GetLastError ();
6289 ERR ("HeapFree failed with code %i\n", ret);
6290 r = RegCloseKey (hkSubKey);
6291 if (r != ERROR_SUCCESS)
6292 WARN ("RegCloseKey returned %i\n", r);
6293 return ret;
6296 ret = RegCloseKey (hkSubKey);
6297 if (ret != ERROR_SUCCESS)
6299 ERR ("RegCloseKey returned %i\n", ret);
6300 return ret;
6303 return ERROR_SUCCESS;
6306 /*******************************************************************************
6307 * EnumPrinterDataExA [WINSPOOL.@]
6309 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6310 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6311 * what Windows 2000 SP1 does.
6314 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6315 LPBYTE pEnumValues, DWORD cbEnumValues,
6316 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6318 INT len;
6319 LPWSTR pKeyNameW;
6320 DWORD ret, dwIndex, dwBufSize;
6321 HANDLE hHeap;
6322 LPSTR pBuffer;
6324 TRACE ("%p %s\n", hPrinter, pKeyName);
6326 if (pKeyName == NULL || *pKeyName == 0)
6327 return ERROR_INVALID_PARAMETER;
6329 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6330 if (len == 0)
6332 ret = GetLastError ();
6333 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6334 return ret;
6337 hHeap = GetProcessHeap ();
6338 if (hHeap == NULL)
6340 ERR ("GetProcessHeap failed\n");
6341 return ERROR_OUTOFMEMORY;
6344 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6345 if (pKeyNameW == NULL)
6347 ERR ("Failed to allocate %i bytes from process heap\n",
6348 (LONG)(len * sizeof (WCHAR)));
6349 return ERROR_OUTOFMEMORY;
6352 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6354 ret = GetLastError ();
6355 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6356 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6357 WARN ("HeapFree failed with code %i\n", GetLastError ());
6358 return ret;
6361 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6362 pcbEnumValues, pnEnumValues);
6363 if (ret != ERROR_SUCCESS)
6365 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6366 WARN ("HeapFree failed with code %i\n", GetLastError ());
6367 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6368 return ret;
6371 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6373 ret = GetLastError ();
6374 ERR ("HeapFree failed with code %i\n", ret);
6375 return ret;
6378 if (*pnEnumValues == 0) /* empty key */
6379 return ERROR_SUCCESS;
6381 dwBufSize = 0;
6382 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6384 PPRINTER_ENUM_VALUESW ppev =
6385 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6387 if (dwBufSize < ppev->cbValueName)
6388 dwBufSize = ppev->cbValueName;
6390 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6391 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6392 dwBufSize = ppev->cbData;
6395 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6397 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6398 if (pBuffer == NULL)
6400 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6401 return ERROR_OUTOFMEMORY;
6404 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6406 PPRINTER_ENUM_VALUESW ppev =
6407 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6409 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6410 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6411 NULL);
6412 if (len == 0)
6414 ret = GetLastError ();
6415 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6416 if (HeapFree (hHeap, 0, pBuffer) == 0)
6417 WARN ("HeapFree failed with code %i\n", GetLastError ());
6418 return ret;
6421 memcpy (ppev->pValueName, pBuffer, len);
6423 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6425 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6426 ppev->dwType != REG_MULTI_SZ)
6427 continue;
6429 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6430 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6431 if (len == 0)
6433 ret = GetLastError ();
6434 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6435 if (HeapFree (hHeap, 0, pBuffer) == 0)
6436 WARN ("HeapFree failed with code %i\n", GetLastError ());
6437 return ret;
6440 memcpy (ppev->pData, pBuffer, len);
6442 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6443 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6446 if (HeapFree (hHeap, 0, pBuffer) == 0)
6448 ret = GetLastError ();
6449 ERR ("HeapFree failed with code %i\n", ret);
6450 return ret;
6453 return ERROR_SUCCESS;
6456 /******************************************************************************
6457 * AbortPrinter (WINSPOOL.@)
6459 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6461 FIXME("(%p), stub!\n", hPrinter);
6462 return TRUE;
6465 /******************************************************************************
6466 * AddPortA (WINSPOOL.@)
6468 * See AddPortW.
6471 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6473 LPWSTR nameW = NULL;
6474 LPWSTR monitorW = NULL;
6475 DWORD len;
6476 BOOL res;
6478 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6480 if (pName) {
6481 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6482 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6483 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6486 if (pMonitorName) {
6487 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6488 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6489 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6491 res = AddPortW(nameW, hWnd, monitorW);
6492 HeapFree(GetProcessHeap(), 0, nameW);
6493 HeapFree(GetProcessHeap(), 0, monitorW);
6494 return res;
6497 /******************************************************************************
6498 * AddPortW (WINSPOOL.@)
6500 * Add a Port for a specific Monitor
6502 * PARAMS
6503 * pName [I] Servername or NULL (local Computer)
6504 * hWnd [I] Handle to parent Window for the Dialog-Box
6505 * pMonitorName [I] Name of the Monitor that manage the Port
6507 * RETURNS
6508 * Success: TRUE
6509 * Failure: FALSE
6512 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6514 monitor_t * pm;
6515 monitor_t * pui;
6516 DWORD res;
6518 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6520 if (pName && pName[0]) {
6521 SetLastError(ERROR_INVALID_PARAMETER);
6522 return FALSE;
6525 if (!pMonitorName) {
6526 SetLastError(RPC_X_NULL_REF_POINTER);
6527 return FALSE;
6530 /* an empty Monitorname is Invalid */
6531 if (!pMonitorName[0]) {
6532 SetLastError(ERROR_NOT_SUPPORTED);
6533 return FALSE;
6536 pm = monitor_load(pMonitorName, NULL);
6537 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
6538 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
6539 TRACE("got %d with %u\n", res, GetLastError());
6540 res = TRUE;
6542 else
6544 pui = monitor_loadui(pm);
6545 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
6546 TRACE("use %p: %s\n", pui, debugstr_w(pui->dllname));
6547 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
6548 TRACE("got %d with %u\n", res, GetLastError());
6549 res = TRUE;
6551 else
6553 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName),
6554 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
6556 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6557 SetLastError(ERROR_NOT_SUPPORTED);
6558 res = FALSE;
6560 monitor_unload(pui);
6562 monitor_unload(pm);
6563 TRACE("returning %d with %u\n", res, GetLastError());
6564 return res;
6567 /******************************************************************************
6568 * AddPortExA (WINSPOOL.@)
6570 * See AddPortExW.
6573 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6575 PORT_INFO_2W pi2W;
6576 PORT_INFO_2A * pi2A;
6577 LPWSTR nameW = NULL;
6578 LPWSTR monitorW = NULL;
6579 DWORD len;
6580 BOOL res;
6582 pi2A = (PORT_INFO_2A *) pBuffer;
6584 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6585 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6587 if ((level < 1) || (level > 2)) {
6588 SetLastError(ERROR_INVALID_LEVEL);
6589 return FALSE;
6592 if (!pi2A) {
6593 SetLastError(ERROR_INVALID_PARAMETER);
6594 return FALSE;
6597 if (pName) {
6598 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6599 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6600 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6603 if (pMonitorName) {
6604 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6605 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6606 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6609 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6611 if (pi2A->pPortName) {
6612 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6613 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6614 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6617 if (level > 1) {
6618 if (pi2A->pMonitorName) {
6619 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6620 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6621 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6624 if (pi2A->pDescription) {
6625 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6626 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6627 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6629 pi2W.fPortType = pi2A->fPortType;
6630 pi2W.Reserved = pi2A->Reserved;
6633 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6635 HeapFree(GetProcessHeap(), 0, nameW);
6636 HeapFree(GetProcessHeap(), 0, monitorW);
6637 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6638 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6639 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6640 return res;
6644 /******************************************************************************
6645 * AddPortExW (WINSPOOL.@)
6647 * Add a Port for a specific Monitor, without presenting a user interface
6649 * PARAMS
6650 * pName [I] Servername or NULL (local Computer)
6651 * level [I] Structure-Level (1 or 2) for pBuffer
6652 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6653 * pMonitorName [I] Name of the Monitor that manage the Port
6655 * RETURNS
6656 * Success: TRUE
6657 * Failure: FALSE
6660 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6662 PORT_INFO_2W * pi2;
6663 monitor_t * pm;
6664 DWORD res = FALSE;
6666 pi2 = (PORT_INFO_2W *) pBuffer;
6668 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6669 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6670 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6671 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6674 if ((level < 1) || (level > 2)) {
6675 SetLastError(ERROR_INVALID_LEVEL);
6676 return FALSE;
6679 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6680 SetLastError(ERROR_INVALID_PARAMETER);
6681 return FALSE;
6684 /* load the Monitor */
6685 pm = monitor_load(pMonitorName, NULL);
6686 if (!pm) {
6687 SetLastError(ERROR_INVALID_PARAMETER);
6688 return FALSE;
6691 if (pm->monitor && pm->monitor->pfnAddPortEx) {
6692 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
6693 TRACE("got %u with %u\n", res, GetLastError());
6695 else
6697 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName), pm->monitor);
6699 monitor_unload(pm);
6700 return res;
6703 /******************************************************************************
6704 * AddPrinterConnectionA (WINSPOOL.@)
6706 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6708 FIXME("%s\n", debugstr_a(pName));
6709 return FALSE;
6712 /******************************************************************************
6713 * AddPrinterConnectionW (WINSPOOL.@)
6715 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6717 FIXME("%s\n", debugstr_w(pName));
6718 return FALSE;
6721 /******************************************************************************
6722 * AddPrinterDriverExW (WINSPOOL.@)
6724 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6726 * PARAMS
6727 * pName [I] Servername or NULL (local Computer)
6728 * level [I] Level for the supplied DRIVER_INFO_*W struct
6729 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6730 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6732 * RESULTS
6733 * Success: TRUE
6734 * Failure: FALSE
6737 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6739 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6741 if ((backend == NULL) && !load_backend()) return FALSE;
6743 if (level < 2 || level == 5 || level == 7 || level > 8) {
6744 SetLastError(ERROR_INVALID_LEVEL);
6745 return FALSE;
6748 if (!pDriverInfo) {
6749 SetLastError(ERROR_INVALID_PARAMETER);
6750 return FALSE;
6753 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6756 /******************************************************************************
6757 * AddPrinterDriverExA (WINSPOOL.@)
6759 * See AddPrinterDriverExW.
6762 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6764 DRIVER_INFO_8A *diA;
6765 DRIVER_INFO_8W diW;
6766 LPWSTR nameW = NULL;
6767 DWORD lenA;
6768 DWORD len;
6769 DWORD res = FALSE;
6771 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6773 diA = (DRIVER_INFO_8A *) pDriverInfo;
6774 ZeroMemory(&diW, sizeof(diW));
6776 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6777 SetLastError(ERROR_INVALID_LEVEL);
6778 return FALSE;
6781 if (diA == NULL) {
6782 SetLastError(ERROR_INVALID_PARAMETER);
6783 return FALSE;
6786 /* convert servername to unicode */
6787 if (pName) {
6788 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6789 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6790 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6793 /* common fields */
6794 diW.cVersion = diA->cVersion;
6796 if (diA->pName) {
6797 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6798 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6799 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6802 if (diA->pEnvironment) {
6803 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6804 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6805 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6808 if (diA->pDriverPath) {
6809 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6810 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6811 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6814 if (diA->pDataFile) {
6815 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6816 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6817 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6820 if (diA->pConfigFile) {
6821 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6822 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6823 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6826 if ((Level > 2) && diA->pDependentFiles) {
6827 lenA = multi_sz_lenA(diA->pDependentFiles);
6828 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6829 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6830 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6833 if ((Level > 2) && diA->pMonitorName) {
6834 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6835 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6836 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6839 if ((Level > 3) && diA->pDefaultDataType) {
6840 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6841 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6842 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6845 if ((Level > 3) && diA->pszzPreviousNames) {
6846 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6847 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6848 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6849 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6852 if ((Level > 5) && diA->pszMfgName) {
6853 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6854 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6855 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6858 if ((Level > 5) && diA->pszOEMUrl) {
6859 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6860 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6861 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6864 if ((Level > 5) && diA->pszHardwareID) {
6865 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6866 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6867 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6870 if ((Level > 5) && diA->pszProvider) {
6871 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6872 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6873 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6876 if (Level > 7) {
6877 FIXME("level %u is incomplete\n", Level);
6880 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6881 TRACE("got %u with %u\n", res, GetLastError());
6882 HeapFree(GetProcessHeap(), 0, nameW);
6883 HeapFree(GetProcessHeap(), 0, diW.pName);
6884 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6885 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6886 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6887 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6888 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6889 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6890 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6891 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6892 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6893 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6894 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6895 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6897 TRACE("=> %u with %u\n", res, GetLastError());
6898 return res;
6901 /******************************************************************************
6902 * ConfigurePortA (WINSPOOL.@)
6904 * See ConfigurePortW.
6907 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6909 LPWSTR nameW = NULL;
6910 LPWSTR portW = NULL;
6911 INT len;
6912 DWORD res;
6914 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6916 /* convert servername to unicode */
6917 if (pName) {
6918 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6919 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6920 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6923 /* convert portname to unicode */
6924 if (pPortName) {
6925 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6926 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6927 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6930 res = ConfigurePortW(nameW, hWnd, portW);
6931 HeapFree(GetProcessHeap(), 0, nameW);
6932 HeapFree(GetProcessHeap(), 0, portW);
6933 return res;
6936 /******************************************************************************
6937 * ConfigurePortW (WINSPOOL.@)
6939 * Display the Configuration-Dialog for a specific Port
6941 * PARAMS
6942 * pName [I] Servername or NULL (local Computer)
6943 * hWnd [I] Handle to parent Window for the Dialog-Box
6944 * pPortName [I] Name of the Port, that should be configured
6946 * RETURNS
6947 * Success: TRUE
6948 * Failure: FALSE
6951 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6953 monitor_t * pm;
6954 monitor_t * pui;
6955 DWORD res;
6957 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6959 if (pName && pName[0]) {
6960 SetLastError(ERROR_INVALID_PARAMETER);
6961 return FALSE;
6964 if (!pPortName) {
6965 SetLastError(RPC_X_NULL_REF_POINTER);
6966 return FALSE;
6969 /* an empty Portname is Invalid, but can popup a Dialog */
6970 if (!pPortName[0]) {
6971 SetLastError(ERROR_NOT_SUPPORTED);
6972 return FALSE;
6975 pm = monitor_load_by_port(pPortName);
6976 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6977 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6978 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6979 TRACE("got %d with %u\n", res, GetLastError());
6981 else
6983 pui = monitor_loadui(pm);
6984 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6985 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6986 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6987 TRACE("got %d with %u\n", res, GetLastError());
6989 else
6991 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6992 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
6994 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6995 SetLastError(ERROR_NOT_SUPPORTED);
6996 res = FALSE;
6998 monitor_unload(pui);
7000 monitor_unload(pm);
7002 TRACE("returning %d with %u\n", res, GetLastError());
7003 return res;
7006 /******************************************************************************
7007 * ConnectToPrinterDlg (WINSPOOL.@)
7009 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
7011 FIXME("%p %x\n", hWnd, Flags);
7012 return NULL;
7015 /******************************************************************************
7016 * DeletePrinterConnectionA (WINSPOOL.@)
7018 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
7020 FIXME("%s\n", debugstr_a(pName));
7021 return TRUE;
7024 /******************************************************************************
7025 * DeletePrinterConnectionW (WINSPOOL.@)
7027 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
7029 FIXME("%s\n", debugstr_w(pName));
7030 return TRUE;
7033 /******************************************************************************
7034 * DeletePrinterDriverExW (WINSPOOL.@)
7036 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
7037 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7039 HKEY hkey_drivers;
7040 BOOL ret = FALSE;
7042 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
7043 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
7045 if(pName && pName[0])
7047 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
7048 SetLastError(ERROR_INVALID_PARAMETER);
7049 return FALSE;
7052 if(dwDeleteFlag)
7054 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
7055 SetLastError(ERROR_INVALID_PARAMETER);
7056 return FALSE;
7059 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
7061 if(!hkey_drivers)
7063 ERR("Can't open drivers key\n");
7064 return FALSE;
7067 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
7068 ret = TRUE;
7070 RegCloseKey(hkey_drivers);
7072 return ret;
7075 /******************************************************************************
7076 * DeletePrinterDriverExA (WINSPOOL.@)
7078 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
7079 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7081 UNICODE_STRING NameW, EnvW, DriverW;
7082 BOOL ret;
7084 asciitounicode(&NameW, pName);
7085 asciitounicode(&EnvW, pEnvironment);
7086 asciitounicode(&DriverW, pDriverName);
7088 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
7090 RtlFreeUnicodeString(&DriverW);
7091 RtlFreeUnicodeString(&EnvW);
7092 RtlFreeUnicodeString(&NameW);
7094 return ret;
7097 /******************************************************************************
7098 * DeletePrinterDataExW (WINSPOOL.@)
7100 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
7101 LPCWSTR pValueName)
7103 FIXME("%p %s %s\n", hPrinter,
7104 debugstr_w(pKeyName), debugstr_w(pValueName));
7105 return ERROR_INVALID_PARAMETER;
7108 /******************************************************************************
7109 * DeletePrinterDataExA (WINSPOOL.@)
7111 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
7112 LPCSTR pValueName)
7114 FIXME("%p %s %s\n", hPrinter,
7115 debugstr_a(pKeyName), debugstr_a(pValueName));
7116 return ERROR_INVALID_PARAMETER;
7119 /******************************************************************************
7120 * DeletePrintProcessorA (WINSPOOL.@)
7122 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
7124 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7125 debugstr_a(pPrintProcessorName));
7126 return TRUE;
7129 /******************************************************************************
7130 * DeletePrintProcessorW (WINSPOOL.@)
7132 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
7134 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7135 debugstr_w(pPrintProcessorName));
7136 return TRUE;
7139 /******************************************************************************
7140 * DeletePrintProvidorA (WINSPOOL.@)
7142 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
7144 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7145 debugstr_a(pPrintProviderName));
7146 return TRUE;
7149 /******************************************************************************
7150 * DeletePrintProvidorW (WINSPOOL.@)
7152 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
7154 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7155 debugstr_w(pPrintProviderName));
7156 return TRUE;
7159 /******************************************************************************
7160 * EnumFormsA (WINSPOOL.@)
7162 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7163 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7165 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7166 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7167 return FALSE;
7170 /******************************************************************************
7171 * EnumFormsW (WINSPOOL.@)
7173 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7174 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7176 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7177 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7178 return FALSE;
7181 /*****************************************************************************
7182 * EnumMonitorsA [WINSPOOL.@]
7184 * See EnumMonitorsW.
7187 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7188 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7190 BOOL res;
7191 LPBYTE bufferW = NULL;
7192 LPWSTR nameW = NULL;
7193 DWORD needed = 0;
7194 DWORD numentries = 0;
7195 INT len;
7197 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7198 cbBuf, pcbNeeded, pcReturned);
7200 /* convert servername to unicode */
7201 if (pName) {
7202 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7203 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7204 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7206 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7207 needed = cbBuf * sizeof(WCHAR);
7208 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7209 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7211 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7212 if (pcbNeeded) needed = *pcbNeeded;
7213 /* HeapReAlloc return NULL, when bufferW was NULL */
7214 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7215 HeapAlloc(GetProcessHeap(), 0, needed);
7217 /* Try again with the large Buffer */
7218 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7220 numentries = pcReturned ? *pcReturned : 0;
7221 needed = 0;
7223 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7224 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7226 if (res) {
7227 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7228 DWORD entrysize = 0;
7229 DWORD index;
7230 LPSTR ptr;
7231 LPMONITOR_INFO_2W mi2w;
7232 LPMONITOR_INFO_2A mi2a;
7234 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7235 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7237 /* First pass: calculate the size for all Entries */
7238 mi2w = (LPMONITOR_INFO_2W) bufferW;
7239 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7240 index = 0;
7241 while (index < numentries) {
7242 index++;
7243 needed += entrysize; /* MONITOR_INFO_?A */
7244 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7246 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7247 NULL, 0, NULL, NULL);
7248 if (Level > 1) {
7249 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7250 NULL, 0, NULL, NULL);
7251 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7252 NULL, 0, NULL, NULL);
7254 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7255 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7256 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7259 /* check for errors and quit on failure */
7260 if (cbBuf < needed) {
7261 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7262 res = FALSE;
7263 goto emA_cleanup;
7265 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7266 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7267 cbBuf -= len ; /* free Bytes in the user-Buffer */
7268 mi2w = (LPMONITOR_INFO_2W) bufferW;
7269 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7270 index = 0;
7271 /* Second Pass: Fill the User Buffer (if we have one) */
7272 while ((index < numentries) && pMonitors) {
7273 index++;
7274 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7275 mi2a->pName = ptr;
7276 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7277 ptr, cbBuf , NULL, NULL);
7278 ptr += len;
7279 cbBuf -= len;
7280 if (Level > 1) {
7281 mi2a->pEnvironment = ptr;
7282 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7283 ptr, cbBuf, NULL, NULL);
7284 ptr += len;
7285 cbBuf -= len;
7287 mi2a->pDLLName = ptr;
7288 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7289 ptr, cbBuf, NULL, NULL);
7290 ptr += len;
7291 cbBuf -= len;
7293 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7294 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7295 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7298 emA_cleanup:
7299 if (pcbNeeded) *pcbNeeded = needed;
7300 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7302 HeapFree(GetProcessHeap(), 0, nameW);
7303 HeapFree(GetProcessHeap(), 0, bufferW);
7305 TRACE("returning %d with %d (%d byte for %d entries)\n",
7306 (res), GetLastError(), needed, numentries);
7308 return (res);
7312 /*****************************************************************************
7313 * EnumMonitorsW [WINSPOOL.@]
7315 * Enumerate available Port-Monitors
7317 * PARAMS
7318 * pName [I] Servername or NULL (local Computer)
7319 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7320 * pMonitors [O] PTR to Buffer that receives the Result
7321 * cbBuf [I] Size of Buffer at pMonitors
7322 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7323 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7325 * RETURNS
7326 * Success: TRUE
7327 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7329 * NOTES
7330 * Windows reads the Registry once and cache the Results.
7332 *| Language-Monitors are also installed in the same Registry-Location but
7333 *| they are filtered in Windows (not returned by EnumMonitors).
7334 *| We do no filtering to simplify our Code.
7337 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7338 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7340 DWORD needed = 0;
7341 DWORD numentries = 0;
7342 BOOL res = FALSE;
7344 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7345 cbBuf, pcbNeeded, pcReturned);
7347 if (pName && (lstrlenW(pName))) {
7348 FIXME("for Server %s not implemented\n", debugstr_w(pName));
7349 SetLastError(ERROR_ACCESS_DENIED);
7350 goto emW_cleanup;
7353 /* Level is not checked in win9x */
7354 if (!Level || (Level > 2)) {
7355 WARN("level (%d) is ignored in win9x\n", Level);
7356 SetLastError(ERROR_INVALID_LEVEL);
7357 goto emW_cleanup;
7359 if (!pcbNeeded) {
7360 SetLastError(RPC_X_NULL_REF_POINTER);
7361 goto emW_cleanup;
7364 /* Scan all Monitor-Keys */
7365 numentries = 0;
7366 needed = get_local_monitors(Level, NULL, 0, &numentries);
7368 /* we calculated the needed buffersize. now do the error-checks */
7369 if (cbBuf < needed) {
7370 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7371 goto emW_cleanup;
7373 else if (!pMonitors || !pcReturned) {
7374 SetLastError(RPC_X_NULL_REF_POINTER);
7375 goto emW_cleanup;
7378 /* fill the Buffer with the Monitor-Keys */
7379 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
7380 res = TRUE;
7382 emW_cleanup:
7383 if (pcbNeeded) *pcbNeeded = needed;
7384 if (pcReturned) *pcReturned = numentries;
7386 TRACE("returning %d with %d (%d byte for %d entries)\n",
7387 res, GetLastError(), needed, numentries);
7389 return (res);
7392 /******************************************************************************
7393 * SpoolerInit (WINSPOOL.@)
7395 * Initialize the Spooler
7397 * RETURNS
7398 * Success: TRUE
7399 * Failure: FALSE
7401 * NOTES
7402 * The function fails on windows, when the spooler service is not running
7405 BOOL WINAPI SpoolerInit(void)
7408 if ((backend == NULL) && !load_backend()) return FALSE;
7409 return TRUE;
7412 /******************************************************************************
7413 * XcvDataW (WINSPOOL.@)
7415 * Execute commands in the Printmonitor DLL
7417 * PARAMS
7418 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7419 * pszDataName [i] Name of the command to execute
7420 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7421 * cbInputData [i] Size in Bytes of Buffer at pInputData
7422 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7423 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7424 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7425 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7427 * RETURNS
7428 * Success: TRUE
7429 * Failure: FALSE
7431 * NOTES
7432 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7433 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7435 * Minimal List of commands, that a Printmonitor DLL should support:
7437 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7438 *| "AddPort" : Add a Port
7439 *| "DeletePort": Delete a Port
7441 * Many Printmonitors support additional commands. Examples for localspl.dll:
7442 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7443 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7446 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7447 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7448 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7450 opened_printer_t *printer;
7452 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7453 pInputData, cbInputData, pOutputData,
7454 cbOutputData, pcbOutputNeeded, pdwStatus);
7456 printer = get_opened_printer(hXcv);
7457 if (!printer || (!printer->hXcv)) {
7458 SetLastError(ERROR_INVALID_HANDLE);
7459 return FALSE;
7462 if (!pcbOutputNeeded) {
7463 SetLastError(ERROR_INVALID_PARAMETER);
7464 return FALSE;
7467 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7468 SetLastError(RPC_X_NULL_REF_POINTER);
7469 return FALSE;
7472 *pcbOutputNeeded = 0;
7474 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
7475 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
7477 return TRUE;
7480 /*****************************************************************************
7481 * EnumPrinterDataA [WINSPOOL.@]
7484 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7485 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7486 DWORD cbData, LPDWORD pcbData )
7488 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7489 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7490 return ERROR_NO_MORE_ITEMS;
7493 /*****************************************************************************
7494 * EnumPrinterDataW [WINSPOOL.@]
7497 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7498 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7499 DWORD cbData, LPDWORD pcbData )
7501 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7502 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7503 return ERROR_NO_MORE_ITEMS;
7506 /*****************************************************************************
7507 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7510 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7511 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7512 LPDWORD pcbNeeded, LPDWORD pcReturned)
7514 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7515 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7516 pcbNeeded, pcReturned);
7517 return FALSE;
7520 /*****************************************************************************
7521 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7524 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7525 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7526 LPDWORD pcbNeeded, LPDWORD pcReturned)
7528 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7529 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7530 pcbNeeded, pcReturned);
7531 return FALSE;
7534 /*****************************************************************************
7535 * EnumPrintProcessorsA [WINSPOOL.@]
7538 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7539 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7541 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
7542 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
7543 return FALSE;
7546 /*****************************************************************************
7547 * EnumPrintProcessorsW [WINSPOOL.@]
7550 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7551 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7553 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7554 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
7555 cbBuf, pcbNeeded, pcbReturned);
7556 return FALSE;
7559 /*****************************************************************************
7560 * ExtDeviceMode [WINSPOOL.@]
7563 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7564 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7565 DWORD fMode)
7567 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7568 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7569 debugstr_a(pProfile), fMode);
7570 return -1;
7573 /*****************************************************************************
7574 * FindClosePrinterChangeNotification [WINSPOOL.@]
7577 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7579 FIXME("Stub: %p\n", hChange);
7580 return TRUE;
7583 /*****************************************************************************
7584 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7587 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7588 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7590 FIXME("Stub: %p %x %x %p\n",
7591 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7592 return INVALID_HANDLE_VALUE;
7595 /*****************************************************************************
7596 * FindNextPrinterChangeNotification [WINSPOOL.@]
7599 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7600 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7602 FIXME("Stub: %p %p %p %p\n",
7603 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7604 return FALSE;
7607 /*****************************************************************************
7608 * FreePrinterNotifyInfo [WINSPOOL.@]
7611 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7613 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7614 return TRUE;
7617 /*****************************************************************************
7618 * string_to_buf
7620 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7621 * ansi depending on the unicode parameter.
7623 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7625 if(!str)
7627 *size = 0;
7628 return TRUE;
7631 if(unicode)
7633 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7634 if(*size <= cb)
7636 memcpy(ptr, str, *size);
7637 return TRUE;
7639 return FALSE;
7641 else
7643 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7644 if(*size <= cb)
7646 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7647 return TRUE;
7649 return FALSE;
7653 /*****************************************************************************
7654 * get_job_info_1
7656 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7657 LPDWORD pcbNeeded, BOOL unicode)
7659 DWORD size, left = cbBuf;
7660 BOOL space = (cbBuf > 0);
7661 LPBYTE ptr = buf;
7663 *pcbNeeded = 0;
7665 if(space)
7667 ji1->JobId = job->job_id;
7670 string_to_buf(job->document_title, ptr, left, &size, unicode);
7671 if(space && size <= left)
7673 ji1->pDocument = (LPWSTR)ptr;
7674 ptr += size;
7675 left -= size;
7677 else
7678 space = FALSE;
7679 *pcbNeeded += size;
7681 return space;
7684 /*****************************************************************************
7685 * get_job_info_2
7687 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7688 LPDWORD pcbNeeded, BOOL unicode)
7690 DWORD size, left = cbBuf;
7691 BOOL space = (cbBuf > 0);
7692 LPBYTE ptr = buf;
7694 *pcbNeeded = 0;
7696 if(space)
7698 ji2->JobId = job->job_id;
7701 string_to_buf(job->document_title, ptr, left, &size, unicode);
7702 if(space && size <= left)
7704 ji2->pDocument = (LPWSTR)ptr;
7705 ptr += size;
7706 left -= size;
7708 else
7709 space = FALSE;
7710 *pcbNeeded += size;
7712 return space;
7715 /*****************************************************************************
7716 * get_job_info
7718 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7719 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7721 BOOL ret = FALSE;
7722 DWORD needed = 0, size;
7723 job_t *job;
7724 LPBYTE ptr = pJob;
7726 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7728 EnterCriticalSection(&printer_handles_cs);
7729 job = get_job(hPrinter, JobId);
7730 if(!job)
7731 goto end;
7733 switch(Level)
7735 case 1:
7736 size = sizeof(JOB_INFO_1W);
7737 if(cbBuf >= size)
7739 cbBuf -= size;
7740 ptr += size;
7741 memset(pJob, 0, size);
7743 else
7744 cbBuf = 0;
7745 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7746 needed += size;
7747 break;
7749 case 2:
7750 size = sizeof(JOB_INFO_2W);
7751 if(cbBuf >= size)
7753 cbBuf -= size;
7754 ptr += size;
7755 memset(pJob, 0, size);
7757 else
7758 cbBuf = 0;
7759 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7760 needed += size;
7761 break;
7763 case 3:
7764 size = sizeof(JOB_INFO_3);
7765 if(cbBuf >= size)
7767 cbBuf -= size;
7768 memset(pJob, 0, size);
7769 ret = TRUE;
7771 else
7772 cbBuf = 0;
7773 needed = size;
7774 break;
7776 default:
7777 SetLastError(ERROR_INVALID_LEVEL);
7778 goto end;
7780 if(pcbNeeded)
7781 *pcbNeeded = needed;
7782 end:
7783 LeaveCriticalSection(&printer_handles_cs);
7784 return ret;
7787 /*****************************************************************************
7788 * GetJobA [WINSPOOL.@]
7791 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7792 DWORD cbBuf, LPDWORD pcbNeeded)
7794 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7797 /*****************************************************************************
7798 * GetJobW [WINSPOOL.@]
7801 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7802 DWORD cbBuf, LPDWORD pcbNeeded)
7804 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7807 /*****************************************************************************
7808 * schedule_lpr
7810 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7812 char *unixname, *queue, *cmd;
7813 char fmt[] = "lpr -P%s %s";
7814 DWORD len;
7816 if(!(unixname = wine_get_unix_file_name(filename)))
7817 return FALSE;
7819 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7820 queue = HeapAlloc(GetProcessHeap(), 0, len);
7821 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7823 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7824 sprintf(cmd, fmt, queue, unixname);
7826 TRACE("printing with: %s\n", cmd);
7827 system(cmd);
7829 HeapFree(GetProcessHeap(), 0, cmd);
7830 HeapFree(GetProcessHeap(), 0, queue);
7831 HeapFree(GetProcessHeap(), 0, unixname);
7832 return TRUE;
7835 /*****************************************************************************
7836 * schedule_cups
7838 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7840 #ifdef SONAME_LIBCUPS
7841 if(pcupsPrintFile)
7843 char *unixname, *queue, *doc_titleA;
7844 DWORD len;
7845 BOOL ret;
7847 if(!(unixname = wine_get_unix_file_name(filename)))
7848 return FALSE;
7850 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7851 queue = HeapAlloc(GetProcessHeap(), 0, len);
7852 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7854 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
7855 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
7856 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
7858 TRACE("printing via cups\n");
7859 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
7860 HeapFree(GetProcessHeap(), 0, doc_titleA);
7861 HeapFree(GetProcessHeap(), 0, queue);
7862 HeapFree(GetProcessHeap(), 0, unixname);
7863 return ret;
7865 else
7866 #endif
7868 return schedule_lpr(printer_name, filename);
7872 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7874 LPWSTR filename;
7876 switch(msg)
7878 case WM_INITDIALOG:
7879 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7880 return TRUE;
7882 case WM_COMMAND:
7883 if(HIWORD(wparam) == BN_CLICKED)
7885 if(LOWORD(wparam) == IDOK)
7887 HANDLE hf;
7888 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7889 LPWSTR *output;
7891 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7892 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7894 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7896 WCHAR caption[200], message[200];
7897 int mb_ret;
7899 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7900 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7901 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7902 if(mb_ret == IDCANCEL)
7904 HeapFree(GetProcessHeap(), 0, filename);
7905 return TRUE;
7908 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7909 if(hf == INVALID_HANDLE_VALUE)
7911 WCHAR caption[200], message[200];
7913 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7914 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7915 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7916 HeapFree(GetProcessHeap(), 0, filename);
7917 return TRUE;
7919 CloseHandle(hf);
7920 DeleteFileW(filename);
7921 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7922 *output = filename;
7923 EndDialog(hwnd, IDOK);
7924 return TRUE;
7926 if(LOWORD(wparam) == IDCANCEL)
7928 EndDialog(hwnd, IDCANCEL);
7929 return TRUE;
7932 return FALSE;
7934 return FALSE;
7937 /*****************************************************************************
7938 * get_filename
7940 static BOOL get_filename(LPWSTR *filename)
7942 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7943 file_dlg_proc, (LPARAM)filename) == IDOK;
7946 /*****************************************************************************
7947 * schedule_file
7949 static BOOL schedule_file(LPCWSTR filename)
7951 LPWSTR output = NULL;
7953 if(get_filename(&output))
7955 TRACE("copy to %s\n", debugstr_w(output));
7956 CopyFileW(filename, output, FALSE);
7957 HeapFree(GetProcessHeap(), 0, output);
7958 return TRUE;
7960 return FALSE;
7963 /*****************************************************************************
7964 * schedule_pipe
7966 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7968 #ifdef HAVE_FORK
7969 char *unixname, *cmdA;
7970 DWORD len;
7971 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7972 BOOL ret = FALSE;
7973 char buf[1024];
7975 if(!(unixname = wine_get_unix_file_name(filename)))
7976 return FALSE;
7978 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
7979 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7980 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
7982 TRACE("printing with: %s\n", cmdA);
7984 if((file_fd = open(unixname, O_RDONLY)) == -1)
7985 goto end;
7987 if (pipe(fds))
7989 ERR("pipe() failed!\n");
7990 goto end;
7993 if (fork() == 0)
7995 close(0);
7996 dup2(fds[0], 0);
7997 close(fds[1]);
7999 /* reset signals that we previously set to SIG_IGN */
8000 signal(SIGPIPE, SIG_DFL);
8001 signal(SIGCHLD, SIG_DFL);
8003 execl("/bin/sh", "/bin/sh", "-c", cmdA, (char*)0);
8004 _exit(1);
8007 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
8008 write(fds[1], buf, no_read);
8010 ret = TRUE;
8012 end:
8013 if(file_fd != -1) close(file_fd);
8014 if(fds[0] != -1) close(fds[0]);
8015 if(fds[1] != -1) close(fds[1]);
8017 HeapFree(GetProcessHeap(), 0, cmdA);
8018 HeapFree(GetProcessHeap(), 0, unixname);
8019 return ret;
8020 #else
8021 return FALSE;
8022 #endif
8025 /*****************************************************************************
8026 * schedule_unixfile
8028 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
8030 int in_fd, out_fd, no_read;
8031 char buf[1024];
8032 BOOL ret = FALSE;
8033 char *unixname, *outputA;
8034 DWORD len;
8036 if(!(unixname = wine_get_unix_file_name(filename)))
8037 return FALSE;
8039 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
8040 outputA = HeapAlloc(GetProcessHeap(), 0, len);
8041 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
8043 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
8044 in_fd = open(unixname, O_RDONLY);
8045 if(out_fd == -1 || in_fd == -1)
8046 goto end;
8048 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
8049 write(out_fd, buf, no_read);
8051 ret = TRUE;
8052 end:
8053 if(in_fd != -1) close(in_fd);
8054 if(out_fd != -1) close(out_fd);
8055 HeapFree(GetProcessHeap(), 0, outputA);
8056 HeapFree(GetProcessHeap(), 0, unixname);
8057 return ret;
8060 /*****************************************************************************
8061 * ScheduleJob [WINSPOOL.@]
8064 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
8066 opened_printer_t *printer;
8067 BOOL ret = FALSE;
8068 struct list *cursor, *cursor2;
8070 TRACE("(%p, %x)\n", hPrinter, dwJobID);
8071 EnterCriticalSection(&printer_handles_cs);
8072 printer = get_opened_printer(hPrinter);
8073 if(!printer)
8074 goto end;
8076 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
8078 job_t *job = LIST_ENTRY(cursor, job_t, entry);
8079 HANDLE hf;
8081 if(job->job_id != dwJobID) continue;
8083 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
8084 if(hf != INVALID_HANDLE_VALUE)
8086 PRINTER_INFO_5W *pi5;
8087 DWORD needed;
8088 HKEY hkey;
8089 WCHAR output[1024];
8090 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8091 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8093 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
8094 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
8095 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
8096 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
8097 debugstr_w(pi5->pPortName));
8099 output[0] = 0;
8101 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8102 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
8104 DWORD type, count = sizeof(output);
8105 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
8106 RegCloseKey(hkey);
8108 if(output[0] == '|')
8110 schedule_pipe(output + 1, job->filename);
8112 else if(output[0])
8114 schedule_unixfile(output, job->filename);
8116 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
8118 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
8120 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
8122 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
8124 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
8126 schedule_file(job->filename);
8128 else
8130 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
8132 HeapFree(GetProcessHeap(), 0, pi5);
8133 CloseHandle(hf);
8134 DeleteFileW(job->filename);
8136 list_remove(cursor);
8137 HeapFree(GetProcessHeap(), 0, job->document_title);
8138 HeapFree(GetProcessHeap(), 0, job->filename);
8139 HeapFree(GetProcessHeap(), 0, job);
8140 ret = TRUE;
8141 break;
8143 end:
8144 LeaveCriticalSection(&printer_handles_cs);
8145 return ret;
8148 /*****************************************************************************
8149 * StartDocDlgA [WINSPOOL.@]
8151 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
8153 UNICODE_STRING usBuffer;
8154 DOCINFOW docW;
8155 LPWSTR retW;
8156 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
8157 LPSTR ret = NULL;
8159 docW.cbSize = sizeof(docW);
8160 if (doc->lpszDocName)
8162 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
8163 if (!(docW.lpszDocName = docnameW)) return NULL;
8165 if (doc->lpszOutput)
8167 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
8168 if (!(docW.lpszOutput = outputW)) return NULL;
8170 if (doc->lpszDatatype)
8172 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8173 if (!(docW.lpszDatatype = datatypeW)) return NULL;
8175 docW.fwType = doc->fwType;
8177 retW = StartDocDlgW(hPrinter, &docW);
8179 if(retW)
8181 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8182 ret = HeapAlloc(GetProcessHeap(), 0, len);
8183 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8184 HeapFree(GetProcessHeap(), 0, retW);
8187 HeapFree(GetProcessHeap(), 0, datatypeW);
8188 HeapFree(GetProcessHeap(), 0, outputW);
8189 HeapFree(GetProcessHeap(), 0, docnameW);
8191 return ret;
8194 /*****************************************************************************
8195 * StartDocDlgW [WINSPOOL.@]
8197 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8198 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8199 * port is "FILE:". Also returns the full path if passed a relative path.
8201 * The caller should free the returned string from the process heap.
8203 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8205 LPWSTR ret = NULL;
8206 DWORD len, attr;
8208 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8210 PRINTER_INFO_5W *pi5;
8211 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8212 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8213 return NULL;
8214 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8215 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8216 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8218 HeapFree(GetProcessHeap(), 0, pi5);
8219 return NULL;
8221 HeapFree(GetProcessHeap(), 0, pi5);
8224 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8226 LPWSTR name;
8228 if (get_filename(&name))
8230 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8232 HeapFree(GetProcessHeap(), 0, name);
8233 return NULL;
8235 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8236 GetFullPathNameW(name, len, ret, NULL);
8237 HeapFree(GetProcessHeap(), 0, name);
8239 return ret;
8242 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8243 return NULL;
8245 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8246 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8248 attr = GetFileAttributesW(ret);
8249 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8251 HeapFree(GetProcessHeap(), 0, ret);
8252 ret = NULL;
8254 return ret;