1 /*
2 * WINSPOOL functions
3 *
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
10 *
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.
15 *
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.
20 *
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
24 */
25
26 #include "config.h"
27 #include "wine/port.h"
28
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
42
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"
59
60 #include "ddk/winsplp.h"
61 #include "wspool.h"
62
63 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
64
65 /* ############################### */
66
67 static CRITICAL_SECTION monitor_handles_cs;
68 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
69 {
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") }
73 };
74 static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
75
76
77 static CRITICAL_SECTION printer_handles_cs;
78 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
79 {
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") }
83 };
84 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
85
86 /* ############################### */
87
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;
98
99 typedef struct {
100 DWORD job_id;
101 HANDLE hf;
102 } started_doc_t;
103
104 typedef struct {
105 struct list jobs;
106 LONG ref;
107 } jobqueue_t;
108
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;
117
118 typedef struct {
119 struct list entry;
120 DWORD job_id;
121 WCHAR *filename;
122 WCHAR *document_title;
123 } job_t;
124
125
126 typedef struct {
127 LPCWSTR envname;
128 LPCWSTR subdir;
129 DWORD driverversion;
130 LPCWSTR versionregpath;
131 LPCWSTR versionsubdir;
132 } printenv_t;
133
134 /* ############################### */
135
136 static struct list monitor_handles = LIST_INIT( monitor_handles );
137 static monitor_t * pm_localport;
138
139 static opened_printer_t **printer_handles;
140 static UINT nb_printer_handles;
141 static LONG next_job_id = 1;
142
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 );
150
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 };
157
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};
163
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};
169
170 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
171
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};
177
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};
183
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};
189
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};
195
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};
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};
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};
202 static const WCHAR Version0_SubdirW[] = {'\\','',0};
203 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
204 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
205
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};
208
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};
246
247 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
248
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};
252
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};
255
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)};
260
261
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)};
267
268 /******************************************************************
269 * validate the user-supplied printing-environment [internal]
270 *
271 * PARAMS
272 * env [I] PTR to Environment-String or NULL
273 *
274 * RETURNS
275 * Failure: NULL
276 * Success: PTR to printenv_t
277 *
278 * NOTES
279 * An empty string is handled the same way as NULL.
280 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
281 *
282 */
283
284 static const printenv_t * validate_envW(LPCWSTR env)
285 {
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};
290
291 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
292
293 const printenv_t *result = NULL;
294 unsigned int i;
295
296 TRACE("testing %s\n", debugstr_w(env));
297 if (env && env[0])
298 {
299 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
300 {
301 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
302 {
303 result = all_printenv[i];
304 break;
305 }
306 }
307
308 if (result == NULL) {
309 FIXME("unsupported Environment: %s\n", debugstr_w(env));
310 SetLastError(ERROR_INVALID_ENVIRONMENT);
311 }
312 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
313 }
314 else
315 {
316 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
317 }
318 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
319
320 return result;
321 }
322
323
324 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
325 if passed a NULL string. This returns NULLs to the result.
326 */
327 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
328 {
329 if ( (src) )
330 {
331 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
332 return usBufferPtr->Buffer;
333 }
334 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
335 return NULL;
336 }
337
338 static LPWSTR strdupW(LPCWSTR p)
339 {
340 LPWSTR ret;
341 DWORD len;
342
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;
348 }
349
350 static LPSTR strdupWtoA( LPCWSTR str )
351 {
352 LPSTR ret;
353 INT len;
354
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;
360 }
361
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).
366 */
367 #if 0
368 static int multi_sz_lenW(const WCHAR *str)
369 {
370 const WCHAR *ptr = str;
371 if(!str) return 0;
372 do
373 {
374 ptr += lstrlenW(ptr) + 1;
375 } while(*ptr);
376
377 return (ptr - str + 1) * sizeof(WCHAR);
378 }
379 #endif
380 /* ################################ */
381
382 static int multi_sz_lenA(const char *str)
383 {
384 const char *ptr = str;
385 if(!str) return 0;
386 do
387 {
388 ptr += lstrlenA(ptr) + 1;
389 } while(*ptr);
390
391 return ptr - str + 1;
392 }
393
394 static void
395 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
396 char qbuf[200];
397
398 /* If forcing, or no profile string entry for device yet, set the entry
399 *
400 * The always change entry if not WINEPS yet is discussable.
401 */
402 if (force ||
403 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
404 !strcmp(qbuf,"*") ||
405 !strstr(qbuf,"WINEPS.DRV")
406 ) {
407 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
408 HKEY hkey;
409
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);
415 }
416 HeapFree(GetProcessHeap(),0,buf);
417 }
418 }
419
420 static BOOL add_printer_driver(const char *name)
421 {
422 DRIVER_INFO_3A di3a;
423
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";
430
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;
439
440 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
441 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
442 {
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 ))
449 {
450 return TRUE;
451 }
452 }
453 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a.pDriverPath),
454 debugstr_a(di3a.pEnvironment), GetLastError());
455 return FALSE;
456 }
457
458 #ifdef SONAME_LIBCUPS
459 static typeof(cupsGetDests) *pcupsGetDests;
460 static typeof(cupsGetPPD) *pcupsGetPPD;
461 static typeof(cupsPrintFile) *pcupsPrintFile;
462 static void *cupshandle;
463
464 static BOOL CUPS_LoadPrinters(void)
465 {
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];
473
474 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
475 if (!cupshandle) {
476 TRACE("%s\n", loaderror);
477 return FALSE;
478 }
479 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
480
481 #define DYNCUPS(x) \
482 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
483 if (!p##x) return FALSE;
484
485 DYNCUPS(cupsGetPPD);
486 DYNCUPS(cupsGetDests);
487 DYNCUPS(cupsPrintFile);
488 #undef DYNCUPS
489
490 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
491 ERROR_SUCCESS) {
492 ERR("Can't create Printers key\n");
493 return FALSE;
494 }
495
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);
509 }
510
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);
516 }
517
518 HeapFree(GetProcessHeap(), 0, devline);
519
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?>";
535
536 add_printer_driver(dests[i].name);
537
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;
549
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());
553 }
554 }
555 HeapFree(GetProcessHeap(),0,port);
556
557 hadprinter = TRUE;
558 if (dests[i].is_default) {
559 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
560 haddefault = TRUE;
561 }
562 }
563 if (hadprinter & !haddefault)
564 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
565 RegCloseKey(hkeyPrinters);
566 return hadprinter;
567 }
568 #endif
569
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;
577
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 = "";
588
589 TRACE("name=%s entry=%s\n",name, pent);
590
591 if(ispunct(*name)) { /* a tc entry, not a real printer */
592 TRACE("skipping tc entry\n");
593 goto end;
594 }
595
596 if(strstr(pent,":server")) { /* server only version so skip */
597 TRACE("skipping server entry\n");
598 goto end;
599 }
600
601 /* Determine whether this is a postscript printer. */
602
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++)
614 ;
615 }
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;
620
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;
629 }
630
631 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
632 sprintf(port,"LPR:%s",name);
633
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);
641 }
642
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);
648 }
649
650 HeapFree(GetProcessHeap(),0,devline);
651
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;
657 }
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?>";
671
672 add_printer_driver(devname);
673
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;
685
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());
689 }
690 }
691 RegCloseKey(hkeyPrinters);
692
693 if (isfirst || set_default)
694 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
695
696 end:
697 HeapFree(GetProcessHeap(), 0, port);
698 HeapFree(GetProcessHeap(), 0, name);
699 return ret;
700 }
701
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;
709
710 f = fopen("/etc/printcap","r");
711 if (!f)
712 return FALSE;
713
714 while(fgets(buf,sizeof(buf),f)) {
715 char *start, *end;
716
717 end=strchr(buf,'\n');
718 if (end) *end='\0';
719
720 start = buf;
721 while(isspace(*start)) start++;
722 if(*start == '#' || *start == '\0')
723 continue;
724
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;
729 }
730
731 if (end && *--end == '\\') {
732 *end = '\0';
733 had_bash = TRUE;
734 } else
735 had_bash = FALSE;
736
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);
743 }
744
745 }
746 if(pent) {
747 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
748 HeapFree(GetProcessHeap(),0,pent);
749 }
750 fclose(f);
751 return hadprinter;
752 }
753
754 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
755 {
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;
761 }
762
763 /******************************************************************
764 * monitor_unload [internal]
765 *
766 * release a printmonitor and unload it from memory, when needed
767 *
768 */
769 static void monitor_unload(monitor_t * pm)
770 {
771 if (pm == NULL) return;
772 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
773
774 EnterCriticalSection(&monitor_handles_cs);
775
776 if (pm->refcount) pm->refcount--;
777
778 if (pm->refcount == 0) {
779 list_remove(&pm->entry);
780 FreeLibrary(pm->hdll);
781 HeapFree(GetProcessHeap(), 0, pm->name);
782 HeapFree(GetProcessHeap(), 0, pm->dllname);
783 HeapFree(GetProcessHeap(), 0, pm);
784 }
785 LeaveCriticalSection(&monitor_handles_cs);
786 }
787
788 /******************************************************************
789 * monitor_unloadall [internal]
790 *
791 * release all printmonitors and unload them from memory, when needed
792 */
793
794 static void monitor_unloadall(void)
795 {
796 monitor_t * pm;
797 monitor_t * next;
798
799 EnterCriticalSection(&monitor_handles_cs);
800 /* iterate through the list, with safety against removal */
801 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
802 {
803 monitor_unload(pm);
804 }
805 LeaveCriticalSection(&monitor_handles_cs);
806 }
807
808 /******************************************************************
809 * monitor_load [internal]
810 *
811 * load a printmonitor, get the dllname from the registry, when needed
812 * initialize the monitor and dump found function-pointers
813 *
814 * On failure, SetLastError() is called and NULL is returned
815 */
816
817 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
818 {
819 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
820 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
821 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
822 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
823 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
824
825 monitor_t * pm = NULL;
826 monitor_t * cursor;
827 LPWSTR regroot = NULL;
828 LPWSTR driver = dllname;
829
830 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
831 /* Is the Monitor already loaded? */
832 EnterCriticalSection(&monitor_handles_cs);
833
834 if (name) {
835 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
836 {
837 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
838 pm = cursor;
839 break;
840 }
841 }
842 }
843
844 if (pm == NULL) {
845 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
846 if (pm == NULL) goto cleanup;
847 list_add_tail(&monitor_handles, &pm->entry);
848 }
849 pm->refcount++;
850
851 if (pm->name == NULL) {
852 /* Load the monitor */
853 LPMONITOREX pmonitorEx;
854 DWORD len;
855
856 if (name) {
857 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
858 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
859 }
860
861 if (regroot) {
862 lstrcpyW(regroot, MonitorsW);
863 lstrcatW(regroot, name);
864 /* Get the Driver from the Registry */
865 if (driver == NULL) {
866 HKEY hroot;
867 DWORD namesize;
868 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
869 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
870 &namesize) == ERROR_SUCCESS) {
871 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
872 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
873 }
874 RegCloseKey(hroot);
875 }
876 }
877 }
878
879 pm->name = strdupW(name);
880 pm->dllname = strdupW(driver);
881
882 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
883 monitor_unload(pm);
884 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
885 pm = NULL;
886 goto cleanup;
887 }
888
889 pm->hdll = LoadLibraryW(driver);
890 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
891
892 if (pm->hdll == NULL) {
893 monitor_unload(pm);
894 SetLastError(ERROR_MOD_NOT_FOUND);
895 pm = NULL;
896 goto cleanup;
897 }
898
899 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
900 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
901 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
902 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
903 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
904
905
906 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
907 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
908 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
909 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
910 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
911
912 if (pInitializePrintMonitorUI != NULL) {
913 pm->monitorUI = pInitializePrintMonitorUI();
914 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
915 if (pm->monitorUI) {
916 TRACE( "0x%08x: dwMonitorSize (%d)\n",
917 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
918
919 }
920 }
921
922 if (pInitializePrintMonitor && regroot) {
923 pmonitorEx = pInitializePrintMonitor(regroot);
924 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
925 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
926
927 if (pmonitorEx) {
928 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
929 pm->monitor = &(pmonitorEx->Monitor);
930 }
931 }
932
933 if (pm->monitor) {
934 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
935
936 }
937
938 if (!pm->monitor && regroot) {
939 if (pInitializePrintMonitor2 != NULL) {
940 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
941 }
942 if (pInitializeMonitorEx != NULL) {
943 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
944 }
945 if (pInitializeMonitor != NULL) {
946 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
947 }
948 }
949 if (!pm->monitor && !pm->monitorUI) {
950 monitor_unload(pm);
951 SetLastError(ERROR_PROC_NOT_FOUND);
952 pm = NULL;
953 }
954 }
955 cleanup:
956 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
957 pm->refcount++;
958 pm_localport = pm;
959 }
960 LeaveCriticalSection(&monitor_handles_cs);
961 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
962 HeapFree(GetProcessHeap(), 0, regroot);
963 TRACE("=> %p\n", pm);
964 return pm;
965 }
966
967 /******************************************************************
968 * monitor_loadall [internal]
969 *
970 * Load all registered monitors
971 *
972 */
973 static DWORD monitor_loadall(void)
974 {
975 monitor_t * pm;
976 DWORD registered = 0;
977 DWORD loaded = 0;
978 HKEY hmonitors;
979 WCHAR buffer[MAX_PATH];
980 DWORD id = 0;
981
982 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hmonitors) == ERROR_SUCCESS) {
983 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, ®istered, NULL, NULL,
984 NULL, NULL, NULL, NULL, NULL);
985
986 TRACE("%d monitors registered\n", registered);
987
988 EnterCriticalSection(&monitor_handles_cs);
989 while (id < registered) {
990 buffer[0] = '\0';
991 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
992 pm = monitor_load(buffer, NULL);
993 if (pm) loaded++;
994 id++;
995 }
996 LeaveCriticalSection(&monitor_handles_cs);
997 RegCloseKey(hmonitors);
998 }
999 TRACE("%d monitors loaded\n", loaded);
1000 return loaded;
1001 }
1002
1003 /******************************************************************
1004 * monitor_loadui [internal]
1005 *
1006 * load the userinterface-dll for a given portmonitor
1007 *
1008 * On failure, NULL is returned
1009 */
1010
1011 static monitor_t * monitor_loadui(monitor_t * pm)
1012 {
1013 monitor_t * pui = NULL;
1014 LPWSTR buffer[MAX_PATH];
1015 HANDLE hXcv;
1016 DWORD len;
1017 DWORD res;
1018
1019 if (pm == NULL) return NULL;
1020 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
1021
1022 /* Try the Portmonitor first; works for many monitors */
1023 if (pm->monitorUI) {
1024 EnterCriticalSection(&monitor_handles_cs);
1025 pm->refcount++;
1026 LeaveCriticalSection(&monitor_handles_cs);
1027 return pm;
1028 }
1029
1030 /* query the userinterface-dllname from the Portmonitor */
1031 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
1032 /* building (",XcvMonitor %s",pm->name) not needed yet */
1033 res = pm->monitor->pfnXcvOpenPort(emptyStringW, SERVER_ACCESS_ADMINISTER, &hXcv);
1034 TRACE("got %u with %p\n", res, hXcv);
1035 if (res) {
1036 res = pm->monitor->pfnXcvDataPort(hXcv, MonitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
1037 TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
1038 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
1039 pm->monitor->pfnXcvClosePort(hXcv);
1040 }
1041 }
1042 return pui;
1043 }
1044
1045
1046 /******************************************************************
1047 * monitor_load_by_port [internal]
1048 *
1049 * load a printmonitor for a given port
1050 *
1051 * On failure, NULL is returned
1052 */
1053
1054 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1055 {
1056 HKEY hroot;
1057 HKEY hport;
1058 LPWSTR buffer;
1059 monitor_t * pm = NULL;
1060 DWORD registered = 0;
1061 DWORD id = 0;
1062 DWORD len;
1063
1064 TRACE("(%s)\n", debugstr_w(portname));
1065
1066 /* Try the Local Monitor first */
1067 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1068 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1069 /* found the portname */
1070 RegCloseKey(hroot);
1071 return monitor_load(LocalPortW, NULL);
1072 }
1073 RegCloseKey(hroot);
1074 }
1075
1076 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1077 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1078 if (buffer == NULL) return NULL;
1079
1080 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1081 EnterCriticalSection(&monitor_handles_cs);
1082 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, ®istered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1083
1084 while ((pm == NULL) && (id < registered)) {
1085 buffer[0] = '\0';
1086 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1087 TRACE("testing %s\n", debugstr_w(buffer));
1088 len = lstrlenW(buffer);
1089 lstrcatW(buffer, bs_Ports_bsW);
1090 lstrcatW(buffer, portname);
1091 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1092 RegCloseKey(hport);
1093 buffer[len] = '\0'; /* use only the Monitor-Name */
1094 pm = monitor_load(buffer, NULL);
1095 }
1096 id++;
1097 }
1098 LeaveCriticalSection(&monitor_handles_cs);
1099 RegCloseKey(hroot);
1100 }
1101 HeapFree(GetProcessHeap(), 0, buffer);
1102 return pm;
1103 }
1104
1105 /******************************************************************
1106 * enumerate the local Ports from all loaded monitors (internal)
1107 *
1108 * returns the needed size (in bytes) for pPorts
1109 * and *lpreturned is set to number of entries returned in pPorts
1110 *
1111 */
1112 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
1113 {
1114 monitor_t * pm;
1115 LPWSTR ptr;
1116 LPPORT_INFO_2W cache;
1117 LPPORT_INFO_2W out;
1118 LPBYTE pi_buffer = NULL;
1119 DWORD pi_allocated = 0;
1120 DWORD pi_needed;
1121 DWORD pi_index;
1122 DWORD pi_returned;
1123 DWORD res;
1124 DWORD outindex = 0;
1125 DWORD needed;
1126 DWORD numentries;
1127 DWORD entrysize;
1128
1129
1130 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
1131 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
1132
1133 numentries = *lpreturned; /* this is 0, when we scan the registry */
1134 needed = entrysize * numentries;
1135 ptr = (LPWSTR) &pPorts[needed];
1136
1137 numentries = 0;
1138 needed = 0;
1139
1140 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1141 {
1142 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
1143 pi_needed = 0;
1144 pi_returned = 0;
1145 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1146 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
1147 /* Do not use HeapReAlloc (we do not need the old data in the buffer) */
1148 HeapFree(GetProcessHeap(), 0, pi_buffer);
1149 pi_buffer = HeapAlloc(GetProcessHeap(), 0, pi_needed);
1150 pi_allocated = (pi_buffer) ? pi_needed : 0;
1151 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1152 }
1153 TRACE( "(%s) got %d with %d (need %d byte for %d entries)\n",
1154 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
1155
1156 numentries += pi_returned;
1157 needed += pi_needed;
1158
1159 /* fill the output-buffer (pPorts), if we have one */
1160 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
1161 pi_index = 0;
1162 while (pi_returned > pi_index) {
1163 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
1164 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
1165 out->pPortName = ptr;
1166 lstrcpyW(ptr, cache->pPortName);
1167 ptr += (lstrlenW(ptr)+1);
1168 if (level > 1) {
1169 out->pMonitorName = ptr;
1170 lstrcpyW(ptr, cache->pMonitorName);
1171 ptr += (lstrlenW(ptr)+1);
1172
1173 out->pDescription = ptr;
1174 lstrcpyW(ptr, cache->pDescription);
1175 ptr += (lstrlenW(ptr)+1);
1176 out->fPortType = cache->fPortType;
1177 out->Reserved = cache->Reserved;
1178 }
1179 pi_index++;
1180 outindex++;
1181 }
1182 }
1183 }
1184 }
1185 /* the temporary portinfo-buffer is no longer needed */
1186 HeapFree(GetProcessHeap(), 0, pi_buffer);
1187
1188 *lpreturned = numentries;
1189 TRACE("need %d byte for %d entries\n", needed, numentries);
1190 return needed;
1191 }
1192
1193 /******************************************************************
1194 * get_servername_from_name (internal)
1195 *
1196 * for an external server, a copy of the serverpart from the full name is returned
1197 *
1198 */
1199 static LPWSTR get_servername_from_name(LPCWSTR name)
1200 {
1201 LPWSTR server;
1202 LPWSTR ptr;
1203 WCHAR buffer[MAX_PATH];
1204 DWORD len;
1205
1206 if (name == NULL) return NULL;
1207 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1208
1209 server = strdupW(&name[2]); /* skip over both backslash */
1210 if (server == NULL) return NULL;
1211
1212 /* strip '\' and the printername */
1213 ptr = strchrW(server, '\\');
1214 if (ptr) ptr[0] = '\0';
1215
1216 TRACE("found %s\n", debugstr_w(server));
1217
1218 len = sizeof(buffer)/sizeof(buffer[0]);
1219 if (GetComputerNameW(buffer, &len)) {
1220 if (lstrcmpW(buffer, server) == 0) {
1221 /* The requested Servername is our computername */
1222 HeapFree(GetProcessHeap(), 0, server);
1223 return NULL;
1224 }
1225 }
1226 return server;
1227 }
1228
1229 /******************************************************************
1230 * get_basename_from_name (internal)
1231 *
1232 * skip over the serverpart from the full name
1233 *
1234 */
1235 static LPCWSTR get_basename_from_name(LPCWSTR name)
1236 {
1237 if (name == NULL) return NULL;
1238 if ((name[0] == '\\') && (name[1] == '\\')) {
1239 /* skip over the servername and search for the following '\' */
1240 name = strchrW(&name[2], '\\');
1241 if ((name) && (name[1])) {
1242 /* found a separator ('\') followed by a name:
1243 skip over the separator and return the rest */
1244 name++;
1245 }
1246 else
1247 {
1248 /* no basename present (we found only a servername) */
1249 return NULL;
1250 }
1251 }
1252 return name;
1253 }
1254
1255 /******************************************************************
1256 * get_opened_printer_entry
1257 * Get the first place empty in the opened printer table
1258 *
1259 * ToDo:
1260 * - pDefault is ignored
1261 */
1262 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1263 {
1264 UINT_PTR handle = nb_printer_handles, i;
1265 jobqueue_t *queue = NULL;
1266 opened_printer_t *printer = NULL;
1267 LPWSTR servername;
1268 LPCWSTR printername;
1269 HKEY hkeyPrinters;
1270 HKEY hkeyPrinter;
1271 DWORD len;
1272
1273 servername = get_servername_from_name(name);
1274 if (servername) {
1275 FIXME("server %s not supported\n", debugstr_w(servername));
1276 HeapFree(GetProcessHeap(), 0, servername);
1277 SetLastError(ERROR_INVALID_PRINTER_NAME);
1278 return NULL;
1279 }
1280
1281 printername = get_basename_from_name(name);
1282 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1283
1284 /* an empty printername is invalid */
1285 if (printername && (!printername[0])) {
1286 SetLastError(ERROR_INVALID_PARAMETER);
1287 return NULL;
1288 }
1289
1290 EnterCriticalSection(&printer_handles_cs);
1291
1292 for (i = 0; i < nb_printer_handles; i++)
1293 {
1294 if (!printer_handles[i])
1295 {
1296 if(handle == nb_printer_handles)
1297 handle = i;
1298 }
1299 else
1300 {
1301 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1302 queue = printer_handles[i]->queue;
1303 }
1304 }
1305
1306 if (handle >= nb_printer_handles)
1307 {
1308 opened_printer_t **new_array;
1309 if (printer_handles)
1310 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1311 (nb_printer_handles + 16) * sizeof(*new_array) );
1312 else
1313 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1314 (nb_printer_handles + 16) * sizeof(*new_array) );
1315
1316 if (!new_array)
1317 {
1318 handle = 0;
1319 goto end;
1320 }
1321 printer_handles = new_array;
1322 nb_printer_handles += 16;
1323 }
1324
1325 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1326 {
1327 handle = 0;
1328 goto end;
1329 }
1330
1331
1332 /* clone the base name. This is NULL for the printserver */
1333 printer->printername = strdupW(printername);
1334
1335 /* clone the full name */
1336 printer->name = strdupW(name);
1337 if (name && (!printer->name)) {
1338 handle = 0;
1339 goto end;
1340 }
1341
1342 if (printername) {
1343 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1344 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1345 /* OpenPrinter(",XcvMonitor " detected */
1346 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1347 printer->pm = monitor_load(&printername[len], NULL);
1348 if (printer->pm == NULL) {
1349 SetLastError(ERROR_UNKNOWN_PORT);
1350 handle = 0;
1351 goto end;
1352 }
1353 }
1354 else
1355 {
1356 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1357 if (strncmpW( printername, XcvPortW, len) == 0) {
1358 /* OpenPrinter(",XcvPort " detected */
1359 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1360 printer->pm = monitor_load_by_port(&printername[len]);
1361 if (printer->pm == NULL) {
1362 SetLastError(ERROR_UNKNOWN_PORT);
1363 handle = 0;
1364 goto end;
1365 }
1366 }
1367 }
1368
1369 if (printer->pm) {
1370 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1371 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1372 pDefault ? pDefault->DesiredAccess : 0,
1373 &printer->hXcv);
1374 }
1375 if (printer->hXcv == NULL) {
1376 SetLastError(ERROR_INVALID_PARAMETER);
1377 handle = 0;
1378 goto end;
1379 }
1380 }
1381 else
1382 {
1383 /* Does the Printer exist? */
1384 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1385 ERR("Can't create Printers key\n");
1386 handle = 0;
1387 goto end;
1388 }
1389 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1390 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1391 RegCloseKey(hkeyPrinters);
1392 SetLastError(ERROR_INVALID_PRINTER_NAME);
1393 handle = 0;
1394 goto end;
1395 }
1396 RegCloseKey(hkeyPrinter);
1397 RegCloseKey(hkeyPrinters);
1398 }
1399 }
1400 else
1401 {
1402 TRACE("using the local printserver\n");
1403 }
1404
1405 if(queue)
1406 printer->queue = queue;
1407 else
1408 {
1409 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1410 if (!printer->queue) {
1411 handle = 0;
1412 goto end;
1413 }
1414 list_init(&printer->queue->jobs);
1415 printer->queue->ref = 0;
1416 }
1417 InterlockedIncrement(&printer->queue->ref);
1418
1419 printer_handles[handle] = printer;
1420 handle++;
1421 end:
1422 LeaveCriticalSection(&printer_handles_cs);
1423 if (!handle && printer) {
1424 /* Something failed: Free all resources */
1425 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1426 monitor_unload(printer->pm);
1427 HeapFree(GetProcessHeap(), 0, printer->printername);
1428 HeapFree(GetProcessHeap(), 0, printer->name);
1429 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1430 HeapFree(GetProcessHeap(), 0, printer);
1431 }
1432
1433 return (HANDLE)handle;
1434 }
1435
1436 /******************************************************************
1437 * get_opened_printer
1438 * Get the pointer to the opened printer referred by the handle
1439 */
1440 static opened_printer_t *get_opened_printer(HANDLE hprn)
1441 {
1442 UINT_PTR idx = (UINT_PTR)hprn;
1443 opened_printer_t *ret = NULL;
1444
1445 EnterCriticalSection(&printer_handles_cs);
1446
1447 if ((idx > 0) && (idx <= nb_printer_handles)) {
1448 ret = printer_handles[idx - 1];
1449 }
1450 LeaveCriticalSection(&printer_handles_cs);
1451 return ret;
1452 }
1453
1454 /******************************************************************
1455 * get_opened_printer_name
1456 * Get the pointer to the opened printer name referred by the handle
1457 */
1458 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1459 {
1460 opened_printer_t *printer = get_opened_printer(hprn);
1461 if(!printer) return NULL;
1462 return printer->name;
1463 }
1464
1465 /******************************************************************
1466 * WINSPOOL_GetOpenedPrinterRegKey
1467 *
1468 */
1469 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1470 {
1471 LPCWSTR name = get_opened_printer_name(hPrinter);
1472 DWORD ret;
1473 HKEY hkeyPrinters;
1474
1475 if(!name) return ERROR_INVALID_HANDLE;
1476
1477 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1478 ERROR_SUCCESS)
1479 return ret;
1480
1481 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1482 {
1483 ERR("Can't find opened printer %s in registry\n",
1484 debugstr_w(name));
1485 RegCloseKey(hkeyPrinters);
1486 return ERROR_INVALID_PRINTER_NAME; /* ? */
1487 }
1488 RegCloseKey(hkeyPrinters);
1489 return ERROR_SUCCESS;
1490 }
1491
1492 void WINSPOOL_LoadSystemPrinters(void)
1493 {
1494 HKEY hkey, hkeyPrinters;
1495 HANDLE hprn;
1496 DWORD needed, num, i;
1497 WCHAR PrinterName[256];
1498 BOOL done = FALSE;
1499
1500 /* This ensures that all printer entries have a valid Name value. If causes
1501 problems later if they don't. If one is found to be missed we create one
1502 and set it equal to the name of the key */
1503 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1504 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1505 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1506 for(i = 0; i < num; i++) {
1507 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1508 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1509 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1510 set_reg_szW(hkey, NameW, PrinterName);
1511 }
1512 RegCloseKey(hkey);
1513 }
1514 }
1515 }
1516 }
1517 RegCloseKey(hkeyPrinters);
1518 }
1519
1520 /* We want to avoid calling AddPrinter on printers as much as
1521 possible, because on cups printers this will (eventually) lead
1522 to a call to cupsGetPPD which takes forever, even with non-cups
1523 printers AddPrinter takes a while. So we'll tag all printers that
1524 were automatically added last time around, if they still exist
1525 we'll leave them be otherwise we'll delete them. */
1526 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1527 if(needed) {
1528 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1529 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1530 for(i = 0; i < num; i++) {
1531 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1532 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1533 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1534 DWORD dw = 1;
1535 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1536 RegCloseKey(hkey);
1537 }
1538 ClosePrinter(hprn);
1539 }
1540 }
1541 }
1542 }
1543 HeapFree(GetProcessHeap(), 0, pi);
1544 }
1545
1546
1547 #ifdef SONAME_LIBCUPS
1548 done = CUPS_LoadPrinters();
1549 #endif
1550
1551 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1552 PRINTCAP_LoadPrinters();
1553
1554 /* Now enumerate the list again and delete any printers that are still tagged */
1555 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1556 if(needed) {
1557 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1558 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1559 for(i = 0; i < num; i++) {
1560 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1561 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1562 BOOL delete_driver = FALSE;
1563 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1564 DWORD dw, type, size = sizeof(dw);
1565 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1566 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1567 DeletePrinter(hprn);
1568 delete_driver = TRUE;
1569 }
1570 RegCloseKey(hkey);
1571 }
1572 ClosePrinter(hprn);
1573 if(delete_driver)
1574 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1575 }
1576 }
1577 }
1578 }
1579 HeapFree(GetProcessHeap(), 0, pi);
1580 }
1581
1582 return;
1583
1584 }
1585
1586 /******************************************************************
1587 * get_job
1588 *
1589 * Get the pointer to the specified job.
1590 * Should hold the printer_handles_cs before calling.
1591 */
1592 static job_t *get_job(HANDLE hprn, DWORD JobId)
1593 {
1594 opened_printer_t *printer = get_opened_printer(hprn);
1595 job_t *job;
1596
1597 if(!printer) return NULL;
1598 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1599 {
1600 if(job->job_id == JobId)
1601 return job;
1602 }
1603 return NULL;
1604 }
1605
1606 /***********************************************************
1607 * DEVMODEcpyAtoW
1608 */
1609 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1610 {
1611 BOOL Formname;
1612 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1613 DWORD size;
1614
1615 Formname = (dmA->dmSize > off_formname);
1616 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1617 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1618 dmW->dmDeviceName, CCHDEVICENAME);
1619 if(!Formname) {
1620 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1621 dmA->dmSize - CCHDEVICENAME);
1622 } else {
1623 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1624 off_formname - CCHDEVICENAME);
1625 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1626 dmW->dmFormName, CCHFORMNAME);
1627 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1628 (off_formname + CCHFORMNAME));
1629 }
1630 dmW->dmSize = size;
1631 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1632 dmA->dmDriverExtra);
1633 return dmW;
1634 }
1635
1636 /***********************************************************
1637 * DEVMODEdupWtoA
1638 * Creates an ansi copy of supplied devmode
1639 */
1640 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1641 {
1642 LPDEVMODEA dmA;
1643 DWORD size;
1644
1645 if (!dmW) return NULL;
1646 size = dmW->dmSize - CCHDEVICENAME -
1647 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1648
1649 dmA = HeapAlloc(GetProcessHeap(), 0, size + dmW->dmDriverExtra);
1650 if (!dmA) return NULL;
1651
1652 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1653 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1654
1655 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1656 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1657 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1658 }
1659 else
1660 {
1661 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1662 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1663 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1664 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1665
1666 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1667 }
1668
1669 dmA->dmSize = size;
1670 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1671 return dmA;
1672 }
1673
1674 /******************************************************************
1675 * convert_printerinfo_W_to_A [internal]
1676 *
1677 */
1678 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1679 DWORD level, DWORD outlen, DWORD numentries)
1680 {
1681 DWORD id = 0;
1682 LPSTR ptr;
1683 INT len;
1684
1685 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1686
1687 len = pi_sizeof[level] * numentries;
1688 ptr = (LPSTR) out + len;
1689 outlen -= len;
1690
1691 /* copy the numbers of all PRINTER_INFO_* first */
1692 memcpy(out, pPrintersW, len);
1693
1694 while (id < numentries) {
1695 switch (level) {
1696 case 1:
1697 {
1698 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1699 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1700
1701 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1702 if (piW->pDescription) {
1703 piA->pDescription = ptr;
1704 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1705 ptr, outlen, NULL, NULL);
1706 ptr += len;
1707 outlen -= len;
1708 }
1709 if (piW->pName) {
1710 piA->pName = ptr;
1711 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1712 ptr, outlen, NULL, NULL);
1713 ptr += len;
1714 outlen -= len;
1715 }
1716 if (piW->pComment) {
1717 piA->pComment = ptr;
1718 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1719 ptr, outlen, NULL, NULL);
1720 ptr += len;
1721 outlen -= len;
1722 }
1723 break;
1724 }
1725
1726 case 2:
1727 {
1728 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1729 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1730 LPDEVMODEA dmA;
1731
1732 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1733 if (piW->pServerName) {
1734 piA->pServerName = ptr;
1735 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1736 ptr, outlen, NULL, NULL);
1737 ptr += len;
1738 outlen -= len;
1739 }
1740 if (piW->pPrinterName) {
1741 piA->pPrinterName = ptr;
1742 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1743 ptr, outlen, NULL, NULL);
1744 ptr += len;
1745 outlen -= len;
1746 }
1747 if (piW->pShareName) {
1748 piA->pShareName = ptr;
1749 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1750 ptr, outlen, NULL, NULL);
1751 ptr += len;
1752 outlen -= len;
1753 }
1754 if (piW->pPortName) {
1755 piA->pPortName = ptr;
1756 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1757 ptr, outlen, NULL, NULL);
1758 ptr += len;
1759 outlen -= len;
1760 }
1761 if (piW->pDriverName) {
1762 piA->pDriverName = ptr;
1763 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1764 ptr, outlen, NULL, NULL);
1765 ptr += len;
1766 outlen -= len;
1767 }
1768 if (piW->pComment) {
1769 piA->pComment = ptr;
1770 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1771 ptr, outlen, NULL, NULL);
1772 ptr += len;
1773 outlen -= len;
1774 }
1775 if (piW->pLocation) {
1776 piA->pLocation = ptr;
1777 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1778 ptr, outlen, NULL, NULL);
1779 ptr += len;
1780 outlen -= len;
1781 }
1782
1783 dmA = DEVMODEdupWtoA(piW->pDevMode);
1784 if (dmA) {
1785 /* align DEVMODEA to a DWORD boundary */
1786 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1787 ptr += len;
1788 outlen -= len;
1789
1790 piA->pDevMode = (LPDEVMODEA) ptr;
1791 len = dmA->dmSize + dmA->dmDriverExtra;
1792 memcpy(ptr, dmA, len);
1793 HeapFree(GetProcessHeap(), 0, dmA);
1794
1795 ptr += len;
1796 outlen -= len;
1797 }
1798
1799 if (piW->pSepFile) {
1800 piA->pSepFile = ptr;
1801 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1802 ptr, outlen, NULL, NULL);
1803 ptr += len;
1804 outlen -= len;
1805 }
1806 if (piW->pPrintProcessor) {
1807 piA->pPrintProcessor = ptr;
1808 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1809 ptr, outlen, NULL, NULL);
1810 ptr += len;
1811 outlen -= len;
1812 }
1813 if (piW->pDatatype) {
1814 piA->pDatatype = ptr;
1815 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1816 ptr, outlen, NULL, NULL);
1817 ptr += len;
1818 outlen -= len;
1819 }
1820 if (piW->pParameters) {
1821 piA->pParameters = ptr;
1822 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1823 ptr, outlen, NULL, NULL);
1824 ptr += len;
1825 outlen -= len;
1826 }
1827 if (piW->pSecurityDescriptor) {
1828 piA->pSecurityDescriptor = NULL;
1829 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1830 }
1831 break;
1832 }
1833
1834 case 4:
1835 {
1836 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1837 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1838
1839 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1840
1841 if (piW->pPrinterName) {
1842 piA->pPrinterName = ptr;
1843 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1844 ptr, outlen, NULL, NULL);
1845 ptr += len;
1846 outlen -= len;
1847 }
1848 if (piW->pServerName) {
1849 piA->pServerName = ptr;
1850 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1851 ptr, outlen, NULL, NULL);
1852 ptr += len;
1853 outlen -= len;
1854 }
1855 break;
1856 }
1857
1858 case 5:
1859 {
1860 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1861 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1862
1863 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1864
1865 if (piW->pPrinterName) {
1866 piA->pPrinterName = ptr;
1867 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1868 ptr, outlen, NULL, NULL);
1869 ptr += len;
1870 outlen -= len;
1871 }
1872 if (piW->pPortName) {
1873 piA->pPortName = ptr;
1874 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1875 ptr, outlen, NULL, NULL);
1876 ptr += len;
1877 outlen -= len;
1878 }
1879 break;
1880 }
1881
1882 default:
1883 FIXME("for level %u\n", level);
1884 }
1885 pPrintersW += pi_sizeof[level];
1886 out += pi_sizeof[level];
1887 id++;
1888 }
1889 }
1890
1891 /***********************************************************
1892 * PRINTER_INFO_2AtoW
1893 * Creates a unicode copy of PRINTER_INFO_2A on heap
1894 */
1895 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1896 {
1897 LPPRINTER_INFO_2W piW;
1898 UNICODE_STRING usBuffer;
1899
1900 if(!piA) return NULL;
1901 piW = HeapAlloc(heap, 0, sizeof(*piW));
1902 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1903
1904 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1905 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1906 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1907 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1908 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1909 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1910 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1911 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1912 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1913 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1914 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1915 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1916 return piW;
1917 }
1918
1919 /***********************************************************
1920 * FREE_PRINTER_INFO_2W
1921 * Free PRINTER_INFO_2W and all strings
1922 */
1923 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1924 {
1925 if(!piW) return;
1926
1927 HeapFree(heap,0,piW->pServerName);
1928 HeapFree(heap,0,piW->pPrinterName);
1929 HeapFree(heap,0,piW->pShareName);
1930 HeapFree(heap,0,piW->pPortName);
1931 HeapFree(heap,0,piW->pDriverName);
1932 HeapFree(heap,0,piW->pComment);
1933 HeapFree(heap,0,piW->pLocation);
1934 HeapFree(heap,0,piW->pDevMode);
1935 HeapFree(heap,0,piW->pSepFile);
1936 HeapFree(heap,0,piW->pPrintProcessor);
1937 HeapFree(heap,0,piW->pDatatype);
1938 HeapFree(heap,0,piW->pParameters);
1939 HeapFree(heap,0,piW);
1940 return;
1941 }
1942
1943 /******************************************************************
1944 * DeviceCapabilities [WINSPOOL.@]
1945 * DeviceCapabilitiesA [WINSPOOL.@]
1946 *
1947 */
1948 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1949 LPSTR pOutput, LPDEVMODEA lpdm)
1950 {
1951 INT ret;
1952
1953 if (!GDI_CallDeviceCapabilities16)
1954 {
1955 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1956 (LPCSTR)104 );
1957 if (!GDI_CallDeviceCapabilities16) return -1;
1958 }
1959 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1960
1961 /* If DC_PAPERSIZE map POINT16s to POINTs */
1962 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1963 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1964 POINT *pt = (POINT *)pOutput;
1965 INT i;
1966 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1967 for(i = 0; i < ret; i++, pt++)
1968 {
1969 pt->x = tmp[i].x;
1970 pt->y = tmp[i].y;
1971 }
1972 HeapFree( GetProcessHeap(), 0, tmp );
1973 }
1974 return ret;
1975 }
1976
1977
1978 /*****************************************************************************
1979 * DeviceCapabilitiesW [WINSPOOL.@]
1980 *
1981 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1982 *
1983 */
1984 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1985 WORD fwCapability, LPWSTR pOutput,
1986 const DEVMODEW *pDevMode)
1987 {
1988 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1989 LPSTR pDeviceA = strdupWtoA(pDevice);
1990 LPSTR pPortA = strdupWtoA(pPort);
1991 INT ret;
1992
1993 if(pOutput && (fwCapability == DC_BINNAMES ||
1994 fwCapability == DC_FILEDEPENDENCIES ||
1995 fwCapability == DC_PAPERNAMES)) {
1996 /* These need A -> W translation */
1997 INT size = 0, i;
1998 LPSTR pOutputA;
1999 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2000 dmA);
2001 if(ret == -1)
2002 return ret;
2003 switch(fwCapability) {
2004 case DC_BINNAMES:
2005 size = 24;
2006 break;
2007 case DC_PAPERNAMES:
2008 case DC_FILEDEPENDENCIES:
2009 size = 64;
2010 break;
2011 }
2012 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
2013 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2014 dmA);
2015 for(i = 0; i < ret; i++)
2016 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2017 pOutput + (i * size), size);
2018 HeapFree(GetProcessHeap(), 0, pOutputA);
2019 } else {
2020 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2021 (LPSTR)pOutput, dmA);
2022 }
2023 HeapFree(GetProcessHeap(),0,pPortA);
2024 HeapFree(GetProcessHeap(),0,pDeviceA);
2025 HeapFree(GetProcessHeap(),0,dmA);
2026 return ret;
2027 }
2028
2029 /******************************************************************
2030 * DocumentPropertiesA [WINSPOOL.@]
2031 *
2032 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2033 */
2034 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
2035 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
2036 LPDEVMODEA pDevModeInput,DWORD fMode )
2037 {
2038 LPSTR lpName = pDeviceName;
2039 static CHAR port[] = "LPT1:";
2040 LONG ret;
2041
2042 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2043 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
2044 );
2045
2046 if(!pDeviceName) {
2047 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2048 if(!lpNameW) {
2049 ERR("no name from hPrinter?\n");
2050 SetLastError(ERROR_INVALID_HANDLE);
2051 return -1;
2052 }
2053 lpName = strdupWtoA(lpNameW);
2054 }
2055
2056 if (!GDI_CallExtDeviceMode16)
2057 {
2058 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2059 (LPCSTR)102 );
2060 if (!GDI_CallExtDeviceMode16) {
2061 ERR("No CallExtDeviceMode16?\n");
2062 return -1;
2063 }
2064 }
2065 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
2066 pDevModeInput, NULL, fMode);
2067
2068 if(!pDeviceName)
2069 HeapFree(GetProcessHeap(),0,lpName);
2070 return ret;
2071 }
2072
2073
2074 /*****************************************************************************
2075 * DocumentPropertiesW (WINSPOOL.@)
2076 *
2077 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2078 */
2079 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
2080 LPWSTR pDeviceName,
2081 LPDEVMODEW pDevModeOutput,
2082 LPDEVMODEW pDevModeInput, DWORD fMode)
2083 {
2084
2085 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
2086 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
2087 LPDEVMODEA pDevModeOutputA = NULL;
2088 LONG ret;
2089
2090 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2091 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2092 fMode);
2093 if(pDevModeOutput) {
2094 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2095 if(ret < 0) return ret;
2096 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
2097 }
2098 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2099 pDevModeInputA, fMode);
2100 if(pDevModeOutput) {
2101 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2102 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2103 }
2104 if(fMode == 0 && ret > 0)
2105 ret += (CCHDEVICENAME + CCHFORMNAME);
2106 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2107 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2108 return ret;
2109 }
2110
2111 /******************************************************************
2112 * OpenPrinterA [WINSPOOL.@]
2113 *
2114 * See OpenPrinterW.
2115 *
2116 */
2117 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2118 LPPRINTER_DEFAULTSA pDefault)
2119 {
2120 UNICODE_STRING lpPrinterNameW;
2121 UNICODE_STRING usBuffer;
2122 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2123 PWSTR pwstrPrinterNameW;
2124 BOOL ret;
2125
2126 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2127
2128 if(pDefault) {
2129 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2130 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2131 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2132 pDefaultW = &DefaultW;
2133 }
2134 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2135 if(pDefault) {
2136 RtlFreeUnicodeString(&usBuffer);
2137 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2138 }
2139 RtlFreeUnicodeString(&lpPrinterNameW);
2140 return ret;
2141 }
2142
2143 /******************************************************************
2144 * OpenPrinterW [WINSPOOL.@]
2145 *
2146 * Open a Printer / Printserver or a Printer-Object
2147 *
2148 * PARAMS
2149 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2150 * phPrinter [O] The resulting Handle is stored here
2151 * pDefault [I] PTR to Default Printer Settings or NULL
2152 *
2153 * RETURNS
2154 * Success: TRUE
2155 * Failure: FALSE
2156 *
2157 * NOTES
2158 * lpPrinterName is one of:
2159 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2160 *| Printer: "PrinterName"
2161 *| Printer-Object: "PrinterName,Job xxx"
2162 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2163 *| XcvPort: "Servername,XcvPort PortName"
2164 *
2165 * BUGS
2166 *| Printer-Object not supported
2167 *| pDefaults is ignored
2168 *
2169 */
2170 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2171 {
2172
2173 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2174 if (pDefault) {
2175 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2176 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
2177 }
2178
2179 if(!phPrinter) {
2180 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2181 SetLastError(ERROR_INVALID_PARAMETER);
2182 return FALSE;
2183 }
2184
2185 /* Get the unique handle of the printer or Printserver */
2186 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2187 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2188 return (*phPrinter != 0);
2189 }
2190
2191 /******************************************************************
2192 * AddMonitorA [WINSPOOL.@]
2193 *
2194 * See AddMonitorW.
2195 *
2196 */
2197 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2198 {
2199 LPWSTR nameW = NULL;
2200 INT len;
2201 BOOL res;
2202 LPMONITOR_INFO_2A mi2a;
2203 MONITOR_INFO_2W mi2w;
2204
2205 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2206 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2207 debugstr_a(mi2a ? mi2a->pName : NULL),
2208 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2209 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2210
2211 if (Level != 2) {
2212 SetLastError(ERROR_INVALID_LEVEL);
2213 return FALSE;
2214 }
2215
2216 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2217 if (mi2a == NULL) {
2218 return FALSE;
2219 }
2220
2221 if (pName) {
2222 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2223 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2224 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2225 }
2226
2227 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2228 if (mi2a->pName) {
2229 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2230 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2231 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2232 }
2233 if (mi2a->pEnvironment) {
2234 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2235 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2236 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2237 }
2238 if (mi2a->pDLLName) {
2239 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2240 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2241 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2242 }
2243
2244 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2245
2246 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2247 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2248 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2249
2250 HeapFree(GetProcessHeap(), 0, nameW);
2251 return (res);
2252 }
2253
2254 /******************************************************************************
2255 * AddMonitorW [WINSPOOL.@]
2256 *
2257 * Install a Printmonitor
2258 *
2259 * PARAMS
2260 * pName [I] Servername or NULL (local Computer)
2261 * Level [I] Structure-Level (Must be 2)
2262 * pMonitors [I] PTR to MONITOR_INFO_2
2263 *
2264 * RETURNS
2265 * Success: TRUE
2266 * Failure: FALSE
2267 *
2268 * NOTES
2269 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2270 *
2271 */
2272 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2273 {
2274 monitor_t * pm = NULL;
2275 LPMONITOR_INFO_2W mi2w;
2276 HKEY hroot = NULL;
2277 HKEY hentry = NULL;
2278 DWORD disposition;
2279 BOOL res = FALSE;
2280
2281 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2282 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2283 debugstr_w(mi2w ? mi2w->pName : NULL),
2284 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2285 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2286
2287 if (Level != 2) {
2288 SetLastError(ERROR_INVALID_LEVEL);
2289 return FALSE;
2290 }
2291
2292 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2293 if (mi2w == NULL) {
2294 return FALSE;
2295 }
2296
2297 if (pName && (pName[0])) {
2298 FIXME("for server %s not implemented\n", debugstr_w(pName));
2299 SetLastError(ERROR_ACCESS_DENIED);
2300 return FALSE;
2301 }
2302
2303
2304 if (!mi2w->pName || (! mi2w->pName[0])) {
2305 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
2306 SetLastError(ERROR_INVALID_PARAMETER);
2307 return FALSE;
2308 }
2309 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
2310 WARN("Environment %s requested (we support only %s)\n",
2311 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
2312 SetLastError(ERROR_INVALID_ENVIRONMENT);
2313 return FALSE;
2314 }
2315
2316 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
2317 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
2318 SetLastError(ERROR_INVALID_PARAMETER);
2319 return FALSE;
2320 }
2321
2322 /* Load and initialize the monitor. SetLastError() is called on failure */
2323 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
2324 return FALSE;
2325 }
2326 monitor_unload(pm);
2327
2328 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2329 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2330 return FALSE;
2331 }
2332
2333 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
2334 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
2335 &disposition) == ERROR_SUCCESS) {
2336
2337 /* Some installers set options for the port before calling AddMonitor.
2338 We query the "Driver" entry to verify that the monitor is installed,
2339 before we return an error.
2340 When a user installs two print monitors at the same time with the
2341 same name but with a different driver DLL and a task switch comes
2342 between RegQueryValueExW and RegSetValueExW, a race condition
2343 is possible but silently ignored. */
2344
2345 DWORD namesize = 0;
2346
2347 if ((disposition == REG_OPENED_EXISTING_KEY) &&
2348 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
2349 &namesize) == ERROR_SUCCESS)) {
2350 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
2351 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2352 9x: ERROR_ALREADY_EXISTS (183) */
2353 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
2354 }
2355 else
2356 {
2357 INT len;
2358 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
2359 res = (RegSetValueExW(hentry, DriverW, 0,
2360 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
2361 }
2362 RegCloseKey(hentry);
2363 }
2364
2365 RegCloseKey(hroot);
2366 return (res);
2367 }
2368
2369 /******************************************************************
2370 * DeletePrinterDriverA [WINSPOOL.@]
2371 *
2372 */
2373 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2374 {
2375 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2376 }
2377
2378 /******************************************************************
2379 * DeletePrinterDriverW [WINSPOOL.@]
2380 *
2381 */
2382 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2383 {
2384 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2385 }
2386
2387 /******************************************************************
2388 * DeleteMonitorA [WINSPOOL.@]
2389 *
2390 * See DeleteMonitorW.
2391 *
2392 */
2393 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2394 {
2395 LPWSTR nameW = NULL;
2396 LPWSTR EnvironmentW = NULL;
2397 LPWSTR MonitorNameW = NULL;
2398 BOOL res;
2399 INT len;
2400
2401 if (pName) {
2402 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2403 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2404 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2405 }
2406
2407 if (pEnvironment) {
2408 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2409 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2410 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2411 }
2412 if (pMonitorName) {
2413 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2414 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2415 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2416 }
2417
2418 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2419
2420 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2421 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2422 HeapFree(GetProcessHeap(), 0, nameW);
2423 return (res);
2424 }
2425
2426 /******************************************************************
2427 * DeleteMonitorW [WINSPOOL.@]
2428 *
2429 * Delete a specific Printmonitor from a Printing-Environment
2430 *
2431 * PARAMS
2432 * pName [I] Servername or NULL (local Computer)
2433 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2434 * pMonitorName [I] Name of the Monitor, that should be deleted
2435 *
2436 * RETURNS
2437 * Success: TRUE
2438 * Failure: FALSE
2439 *
2440 * NOTES
2441 * pEnvironment is ignored in Windows for the local Computer.
2442 *
2443 */
2444 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2445 {
2446
2447 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2448 debugstr_w(pMonitorName));
2449
2450 if ((backend == NULL) && !load_backend()) return FALSE;
2451
2452 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2453 }
2454
2455
2456 /******************************************************************
2457 * DeletePortA [WINSPOOL.@]
2458 *
2459 * See DeletePortW.
2460 *
2461 */
2462 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2463 {
2464 LPWSTR nameW = NULL;
2465 LPWSTR portW = NULL;
2466 INT len;
2467 DWORD res;
2468
2469 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2470
2471 /* convert servername to unicode */
2472 if (pName) {
2473 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2474 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2475 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2476 }
2477
2478 /* convert portname to unicode */
2479 if (pPortName) {
2480 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2481 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2482 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2483 }
2484
2485 res = DeletePortW(nameW, hWnd, portW);
2486 HeapFree(GetProcessHeap(), 0, nameW);
2487 HeapFree(GetProcessHeap(), 0, portW);
2488 return res;
2489 }
2490
2491 /******************************************************************
2492 * DeletePortW [WINSPOOL.@]
2493 *
2494 * Delete a specific Port
2495 *
2496 * PARAMS
2497 * pName [I] Servername or NULL (local Computer)
2498 * hWnd [I] Handle to parent Window for the Dialog-Box
2499 * pPortName [I] Name of the Port, that should be deleted
2500 *
2501 * RETURNS
2502 * Success: TRUE
2503 * Failure: FALSE
2504 *
2505 */
2506 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2507 {
2508 monitor_t * pm;
2509 monitor_t * pui;
2510 DWORD res;
2511
2512 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2513
2514 if (pName && pName[0]) {
2515 SetLastError(ERROR_INVALID_PARAMETER);
2516 return FALSE;
2517 }
2518
2519 if (!pPortName) {
2520 SetLastError(RPC_X_NULL_REF_POINTER);
2521 return FALSE;
2522 }
2523
2524 /* an empty Portname is Invalid */
2525 if (!pPortName[0]) {
2526 SetLastError(ERROR_NOT_SUPPORTED);
2527 return FALSE;
2528 }
2529
2530 pm = monitor_load_by_port(pPortName);
2531 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2532 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2533 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2534 TRACE("got %d with %u\n", res, GetLastError());
2535 }
2536 else
2537 {
2538 pui = monitor_loadui(pm);
2539 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2540 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2541 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2542 TRACE("got %d with %u\n", res, GetLastError());
2543 }
2544 else
2545 {
2546 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2547 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
2548
2549 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2550 SetLastError(ERROR_NOT_SUPPORTED);
2551 res = FALSE;
2552 }
2553 monitor_unload(pui);
2554 }
2555 monitor_unload(pm);
2556
2557 TRACE("returning %d with %u\n", res, GetLastError());
2558 return res;
2559 }
2560
2561 /******************************************************************************
2562 * SetPrinterW [WINSPOOL.@]
2563 */
2564 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2565 {
2566 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2567 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2568 return FALSE;
2569 }
2570
2571 /******************************************************************************
2572 * WritePrinter [WINSPOOL.@]
2573 */
2574 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2575 {
2576 opened_printer_t *printer;
2577 BOOL ret = FALSE;
2578
2579 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2580
2581 EnterCriticalSection(&printer_handles_cs);
2582 printer = get_opened_printer(hPrinter);
2583 if(!printer)
2584 {
2585 SetLastError(ERROR_INVALID_HANDLE);
2586 goto end;
2587 }
2588
2589 if(!printer->doc)
2590 {
2591 SetLastError(ERROR_SPL_NO_STARTDOC);
2592 goto end;
2593 }
2594
2595 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2596 end:
2597 LeaveCriticalSection(&printer_handles_cs);
2598 return ret;
2599 }
2600
2601 /*****************************************************************************
2602 * AddFormA [WINSPOOL.@]
2603 */
2604 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2605 {
2606 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2607 return 1;
2608 }
2609
2610 /*****************************************************************************
2611 * AddFormW [WINSPOOL.@]
2612 */
2613 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2614 {
2615 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2616 return 1;
2617 }
2618
2619 /*****************************************************************************
2620 * AddJobA [WINSPOOL.@]
2621 */
2622 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2623 {
2624 BOOL ret;
2625 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2626 DWORD needed;
2627
2628 if(Level != 1) {
2629 SetLastError(ERROR_INVALID_LEVEL);
2630 return FALSE;
2631 }
2632
2633 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2634
2635 if(ret) {
2636 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2637 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2638 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2639 if(*pcbNeeded > cbBuf) {
2640 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2641 ret = FALSE;
2642 } else {
2643 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2644 addjobA->JobId = addjobW->JobId;
2645 addjobA->Path = (char *)(addjobA + 1);
2646 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2647 }
2648 }
2649 return ret;
2650 }
2651
2652 /*****************************************************************************
2653 * AddJobW [WINSPOOL.@]
2654 */
2655 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2656 {
2657 opened_printer_t *printer;
2658 job_t *job;
2659 BOOL ret = FALSE;
2660 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2661 static const WCHAR fmtW[] = {'%','s','%','','5','d','.','S','P','L',0};
2662 WCHAR path[MAX_PATH], filename[MAX_PATH];
2663 DWORD len;
2664 ADDJOB_INFO_1W *addjob;
2665
2666 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2667
2668 EnterCriticalSection(&printer_handles_cs);
2669
2670 printer = get_opened_printer(hPrinter);
2671
2672 if(!printer) {
2673 SetLastError(ERROR_INVALID_HANDLE);
2674 goto end;
2675 }
2676
2677 if(Level != 1) {
2678 SetLastError(ERROR_INVALID_LEVEL);
2679 goto end;
2680 }
2681
2682 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2683 if(!job)
2684 goto end;
2685
2686 job->job_id = InterlockedIncrement(&next_job_id);
2687
2688 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2689 if(path[len - 1] != '\\')
2690 path[len++] = '\\';
2691 memcpy(path + len, spool_path, sizeof(spool_path));
2692 sprintfW(filename, fmtW, path, job->job_id);
2693
2694 len = strlenW(filename);
2695 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2696 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2697 job->document_title = strdupW(default_doc_title);
2698 list_add_tail(&printer->queue->jobs, &job->entry);
2699
2700 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2701 if(*pcbNeeded <= cbBuf) {
2702 addjob = (ADDJOB_INFO_1W*)pData;
2703 addjob->JobId = job->job_id;
2704 addjob->Path = (WCHAR *)(addjob + 1);
2705 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2706 ret = TRUE;
2707 } else
2708 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2709
2710 end:
2711 LeaveCriticalSection(&printer_handles_cs);
2712 return ret;
2713 }
2714
2715 /*****************************************************************************
2716 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2717 *
2718 * Return the PATH for the Print-Processors
2719 *
2720 * See GetPrintProcessorDirectoryW.
2721 *
2722 *
2723 */
2724 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2725 DWORD level, LPBYTE Info,
2726 DWORD cbBuf, LPDWORD pcbNeeded)
2727 {
2728 LPWSTR serverW = NULL;
2729 LPWSTR envW = NULL;
2730 BOOL ret;
2731 INT len;
2732
2733 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2734 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2735
2736
2737 if (server) {
2738 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2739 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2740 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2741 }
2742
2743 if (env) {
2744 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2745 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2746 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2747 }
2748
2749 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2750 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2751 */
2752 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2753 cbBuf, pcbNeeded);
2754
2755 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2756 cbBuf, NULL, NULL) > 0;
2757
2758
2759 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2760 HeapFree(GetProcessHeap(), 0, envW);
2761 HeapFree(GetProcessHeap(), 0, serverW);
2762 return ret;
2763 }
2764
2765 /*****************************************************************************
2766 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2767 *
2768 * Return the PATH for the Print-Processors
2769 *
2770 * PARAMS
2771 * server [I] Servername (NT only) or NULL (local Computer)
2772 * env [I] Printing-Environment (see below) or NULL (Default)
2773 * level [I] Structure-Level (must be 1)
2774 * Info [O] PTR to Buffer that receives the Result
2775 * cbBuf [I] Size of Buffer at "Info"
2776 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2777 * required for the Buffer at "Info"
2778 *
2779 * RETURNS
2780 * Success: TRUE and in pcbNeeded the Bytes used in Info
2781 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2782 * if cbBuf is too small
2783 *
2784 * Native Values returned in Info on Success:
2785 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2786 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2787 *| win9x(Windows 4.0): "%winsysdir%"
2788 *
2789 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2790 *
2791 * BUGS
2792 * Only NULL or "" is supported for server
2793 *
2794 */
2795 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2796 DWORD level, LPBYTE Info,
2797 DWORD cbBuf, LPDWORD pcbNeeded)
2798 {
2799 DWORD needed;
2800 const printenv_t * env_t;
2801
2802 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2803 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2804
2805 if(server != NULL && server[0]) {
2806 FIXME("server not supported: %s\n", debugstr_w(server));
2807 SetLastError(ERROR_INVALID_PARAMETER);
2808 return FALSE;
2809 }
2810
2811 env_t = validate_envW(env);
2812 if(!env_t) return FALSE; /* environment invalid or unsupported */
2813
2814 if(level != 1) {
2815 WARN("(Level: %d) is ignored in win9x\n", level);
2816 SetLastError(ERROR_INVALID_LEVEL);
2817 return FALSE;
2818 }
2819
2820 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2821 needed = GetSystemDirectoryW(NULL, 0);
2822 /* add the Size for the Subdirectories */
2823 needed += lstrlenW(spoolprtprocsW);
2824 needed += lstrlenW(env_t->subdir);
2825 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2826
2827 if(pcbNeeded) *pcbNeeded = needed;
2828 TRACE ("required: 0x%x/%d\n", needed, needed);
2829 if (needed > cbBuf) {
2830 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2831 return FALSE;
2832 }
2833 if(pcbNeeded == NULL) {
2834 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2835 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2836 SetLastError(RPC_X_NULL_REF_POINTER);
2837 return FALSE;
2838 }
2839 if(Info == NULL) {
2840 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2841 SetLastError(RPC_X_NULL_REF_POINTER);
2842 return FALSE;
2843 }
2844
2845 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2846 /* add the Subdirectories */
2847 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2848 lstrcatW((LPWSTR) Info, env_t->subdir);
2849 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2850 return TRUE;
2851 }
2852
2853 /*****************************************************************************
2854 * WINSPOOL_OpenDriverReg [internal]
2855 *
2856 * opens the registry for the printer drivers depending on the given input
2857 * variable pEnvironment
2858 *
2859 * RETURNS:
2860 * the opened hkey on success
2861 * NULL on error
2862 */
2863 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2864 {
2865 HKEY retval = NULL;
2866 LPWSTR buffer;
2867 const printenv_t * env;
2868
2869 TRACE("(%s, %d)\n",
2870 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2871
2872 if (!pEnvironment || unicode) {
2873 /* pEnvironment was NULL or an Unicode-String: use it direct */
2874 env = validate_envW(pEnvironment);
2875 }
2876 else
2877 {
2878 /* pEnvironment was an ANSI-String: convert to unicode first */
2879 LPWSTR buffer;
2880 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2881 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2882 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2883 env = validate_envW(buffer);
2884 HeapFree(GetProcessHeap(), 0, buffer);
2885 }
2886 if (!env) return NULL;
2887
2888 buffer = HeapAlloc( GetProcessHeap(), 0,
2889 (strlenW(DriversW) + strlenW(env->envname) +
2890 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2891 if(buffer) {
2892 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2893 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2894 HeapFree(GetProcessHeap(), 0, buffer);
2895 }
2896 return retval;
2897 }
2898
2899 /*****************************************************************************
2900 * AddPrinterW [WINSPOOL.@]
2901 */
2902 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2903 {
2904 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2905 LPDEVMODEA dmA;
2906 LPDEVMODEW dmW;
2907 HANDLE retval;
2908 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2909 LONG size;
2910 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2911 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2912 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2913 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2914 statusW[] = {'S','t','a','t','u','s',0},
2915 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2916
2917 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2918
2919 if(pName != NULL) {
2920 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2921 SetLastError(ERROR_INVALID_PARAMETER);
2922 return 0;
2923 }
2924 if(Level != 2) {
2925 ERR("Level = %d, unsupported!\n", Level);
2926 SetLastError(ERROR_INVALID_LEVEL);
2927 return 0;
2928 }
2929 if(!pPrinter) {
2930 SetLastError(ERROR_INVALID_PARAMETER);
2931 return 0;
2932 }
2933 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2934 ERROR_SUCCESS) {
2935 ERR("Can't create Printers key\n");
2936 return 0;
2937 }
2938 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2939 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2940 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2941 RegCloseKey(hkeyPrinter);
2942 RegCloseKey(hkeyPrinters);
2943 return 0;
2944 }
2945 RegCloseKey(hkeyPrinter);
2946 }
2947 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2948 if(!hkeyDrivers) {
2949 ERR("Can't create Drivers key\n");
2950 RegCloseKey(hkeyPrinters);
2951 return 0;
2952 }
2953 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2954 ERROR_SUCCESS) {
2955 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2956 RegCloseKey(hkeyPrinters);
2957 RegCloseKey(hkeyDrivers);
2958 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2959 return 0;
2960 }
2961 RegCloseKey(hkeyDriver);
2962 RegCloseKey(hkeyDrivers);
2963
2964 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2965 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2966 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2967 RegCloseKey(hkeyPrinters);
2968 return 0;
2969 }
2970
2971 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2972 ERROR_SUCCESS) {
2973 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2974 SetLastError(ERROR_INVALID_PRINTER_NAME);
2975 RegCloseKey(hkeyPrinters);
2976 return 0;
2977 }
2978 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2979 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2980 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2981
2982 /* See if we can load the driver. We may need the devmode structure anyway
2983 *
2984 * FIXME:
2985 * Note that DocumentPropertiesW will briefly try to open the printer we
2986 * just create to find a DEVMODEA struct (it will use the WINEPS default
2987 * one in case it is not there, so we are ok).
2988 */
2989 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2990
2991 if(size < 0) {
2992 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2993 size = sizeof(DEVMODEW);
2994 }
2995 if(pi->pDevMode)
2996 dmW = pi->pDevMode;
2997 else
2998 {
2999 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
3000 dmW->dmSize = size;
3001 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
3002 {
3003 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
3004 HeapFree(GetProcessHeap(),0,dmW);
3005 dmW=NULL;
3006 }
3007 else
3008 {
3009 /* set devmode to printer name */
3010 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
3011 }
3012 }
3013
3014 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
3015 and we support these drivers. NT writes DEVMODEW so somehow
3016 we'll need to distinguish between these when we support NT
3017 drivers */
3018 if (dmW)
3019 {
3020 dmA = DEVMODEdupWtoA(dmW);
3021 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
3022 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
3023 HeapFree(GetProcessHeap(), 0, dmA);
3024 if(!pi->pDevMode)
3025 HeapFree(GetProcessHeap(), 0, dmW);
3026 }
3027 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
3028 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
3029 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
3030 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
3031
3032 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
3033 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
3034 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
3035 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
3036 (LPBYTE)&pi->Priority, sizeof(DWORD));
3037 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
3038 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
3039 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
3040 (LPBYTE)&pi->StartTime, sizeof(DWORD));
3041 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
3042 (LPBYTE)&pi->Status, sizeof(DWORD));
3043 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
3044 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
3045
3046 RegCloseKey(hkeyPrinter);
3047 RegCloseKey(hkeyPrinters);
3048 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
3049 ERR("OpenPrinter failing\n");
3050 return 0;
3051 }
3052 return retval;
3053 }
3054
3055 /*****************************************************************************
3056 * AddPrinterA [WINSPOOL.@]
3057 */
3058 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
3059 {
3060 UNICODE_STRING pNameW;
3061 PWSTR pwstrNameW;
3062 PRINTER_INFO_2W *piW;
3063 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
3064 HANDLE ret;
3065
3066 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
3067 if(Level != 2) {
3068 ERR("Level = %d, unsupported!\n", Level);
3069 SetLastError(ERROR_INVALID_LEVEL);
3070 return 0;
3071 }
3072 pwstrNameW = asciitounicode(&pNameW,pName);
3073 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
3074
3075 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3076
3077 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
3078 RtlFreeUnicodeString(&pNameW);
3079 return ret;
3080 }
3081
3082
3083 /*****************************************************************************
3084 * ClosePrinter [WINSPOOL.@]
3085 */
3086 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3087 {
3088 UINT_PTR i = (UINT_PTR)hPrinter;
3089 opened_printer_t *printer = NULL;
3090 BOOL ret = FALSE;
3091
3092 TRACE("(%p)\n", hPrinter);
3093
3094 EnterCriticalSection(&printer_handles_cs);
3095
3096 if ((i > 0) && (i <= nb_printer_handles))
3097 printer = printer_handles[i - 1];
3098
3099
3100 if(printer)
3101 {
3102 struct list *cursor, *cursor2;
3103
3104 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer->pm,
3105 debugstr_w(printer->pm ? printer->pm->dllname : NULL),
3106 printer->hXcv, debugstr_w(printer->name), printer->doc );
3107
3108 if(printer->doc)
3109 EndDocPrinter(hPrinter);
3110
3111 if(InterlockedDecrement(&printer->queue->ref) == 0)
3112 {
3113 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3114 {
3115 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3116 ScheduleJob(hPrinter, job->job_id);
3117 }
3118 HeapFree(GetProcessHeap(), 0, printer->queue);
3119 }
3120 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
3121 monitor_unload(printer->pm);
3122 HeapFree(GetProcessHeap(), 0, printer->printername);
3123 HeapFree(GetProcessHeap(), 0, printer->name);
3124 HeapFree(GetProcessHeap(), 0, printer);
3125 printer_handles[i - 1] = NULL;
3126 ret = TRUE;
3127 }
3128 LeaveCriticalSection(&printer_handles_cs);
3129 return ret;
3130 }
3131
3132 /*****************************************************************************
3133 * DeleteFormA [WINSPOOL.@]
3134 */
3135 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3136 {
3137 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3138 return 1;
3139 }
3140
3141 /*****************************************************************************
3142 * DeleteFormW [WINSPOOL.@]
3143 */
3144 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3145 {
3146 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3147 return 1;
3148 }
3149
3150 /*****************************************************************************
3151 * DeletePrinter [WINSPOOL.@]
3152 */
3153 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3154 {
3155 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3156 HKEY hkeyPrinters, hkey;
3157
3158 if(!lpNameW) {
3159 SetLastError(ERROR_INVALID_HANDLE);
3160 return FALSE;
3161 }
3162 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3163 RegDeleteTreeW(hkeyPrinters, lpNameW);
3164 RegCloseKey(hkeyPrinters);
3165 }
3166 WriteProfileStringW(devicesW, lpNameW, NULL);
3167 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
3168
3169 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3170 RegDeleteValueW(hkey, lpNameW);
3171 RegCloseKey(hkey);
3172 }
3173
3174 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
3175 RegDeleteValueW(hkey, lpNameW);
3176 RegCloseKey(hkey);
3177 }
3178 return TRUE;
3179 }
3180
3181 /*****************************************************************************
3182 * SetPrinterA [WINSPOOL.@]
3183 */
3184 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3185 DWORD Command)
3186 {
3187 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
3188 return FALSE;
3189 }
3190
3191 /*****************************************************************************
3192 * SetJobA [WINSPOOL.@]
3193 */
3194 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3195 LPBYTE pJob, DWORD Command)
3196 {
3197 BOOL ret;
3198 LPBYTE JobW;
3199 UNICODE_STRING usBuffer;
3200
3201 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3202
3203 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3204 are all ignored by SetJob, so we don't bother copying them */
3205 switch(Level)
3206 {
3207 case 0:
3208 JobW = NULL;