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 LPMONITOR_INFO_2W mi2w;
2275
2276 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2277 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2278 debugstr_w(mi2w ? mi2w->pName : NULL),
2279 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2280 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2281
2282 if ((backend == NULL) && !load_backend()) return FALSE;
2283
2284 if (Level != 2) {
2285 SetLastError(ERROR_INVALID_LEVEL);
2286 return FALSE;
2287 }
2288
2289 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2290 if (mi2w == NULL) {
2291 return FALSE;
2292 }
2293
2294 return backend->fpAddMonitor(pName, Level, pMonitors);
2295 }
2296
2297 /******************************************************************
2298 * DeletePrinterDriverA [WINSPOOL.@]
2299 *
2300 */
2301 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2302 {
2303 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2304 }
2305
2306 /******************************************************************
2307 * DeletePrinterDriverW [WINSPOOL.@]
2308 *
2309 */
2310 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2311 {
2312 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2313 }
2314
2315 /******************************************************************
2316 * DeleteMonitorA [WINSPOOL.@]
2317 *
2318 * See DeleteMonitorW.
2319 *
2320 */
2321 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2322 {
2323 LPWSTR nameW = NULL;
2324 LPWSTR EnvironmentW = NULL;
2325 LPWSTR MonitorNameW = NULL;
2326 BOOL res;
2327 INT len;
2328
2329 if (pName) {
2330 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2331 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2332 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2333 }
2334
2335 if (pEnvironment) {
2336 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2337 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2338 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2339 }
2340 if (pMonitorName) {
2341 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2342 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2343 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2344 }
2345
2346 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2347
2348 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2349 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2350 HeapFree(GetProcessHeap(), 0, nameW);
2351 return (res);
2352 }
2353
2354 /******************************************************************
2355 * DeleteMonitorW [WINSPOOL.@]
2356 *
2357 * Delete a specific Printmonitor from a Printing-Environment
2358 *
2359 * PARAMS
2360 * pName [I] Servername or NULL (local Computer)
2361 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2362 * pMonitorName [I] Name of the Monitor, that should be deleted
2363 *
2364 * RETURNS
2365 * Success: TRUE
2366 * Failure: FALSE
2367 *
2368 * NOTES
2369 * pEnvironment is ignored in Windows for the local Computer.
2370 *
2371 */
2372 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2373 {
2374
2375 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2376 debugstr_w(pMonitorName));
2377
2378 if ((backend == NULL) && !load_backend()) return FALSE;
2379
2380 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2381 }
2382
2383
2384 /******************************************************************
2385 * DeletePortA [WINSPOOL.@]
2386 *
2387 * See DeletePortW.
2388 *
2389 */
2390 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2391 {
2392 LPWSTR nameW = NULL;
2393 LPWSTR portW = NULL;
2394 INT len;
2395 DWORD res;
2396
2397 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2398
2399 /* convert servername to unicode */
2400 if (pName) {
2401 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2402 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2403 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2404 }
2405
2406 /* convert portname to unicode */
2407 if (pPortName) {
2408 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2409 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2410 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2411 }
2412
2413 res = DeletePortW(nameW, hWnd, portW);
2414 HeapFree(GetProcessHeap(), 0, nameW);
2415 HeapFree(GetProcessHeap(), 0, portW);
2416 return res;
2417 }
2418
2419 /******************************************************************
2420 * DeletePortW [WINSPOOL.@]
2421 *
2422 * Delete a specific Port
2423 *
2424 * PARAMS
2425 * pName [I] Servername or NULL (local Computer)
2426 * hWnd [I] Handle to parent Window for the Dialog-Box
2427 * pPortName [I] Name of the Port, that should be deleted
2428 *
2429 * RETURNS
2430 * Success: TRUE
2431 * Failure: FALSE
2432 *
2433 */
2434 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2435 {
2436 monitor_t * pm;
2437 monitor_t * pui;
2438 DWORD res;
2439
2440 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2441
2442 if (pName && pName[0]) {
2443 SetLastError(ERROR_INVALID_PARAMETER);
2444 return FALSE;
2445 }
2446
2447 if (!pPortName) {
2448 SetLastError(RPC_X_NULL_REF_POINTER);
2449 return FALSE;
2450 }
2451
2452 /* an empty Portname is Invalid */
2453 if (!pPortName[0]) {
2454 SetLastError(ERROR_NOT_SUPPORTED);
2455 return FALSE;
2456 }
2457
2458 pm = monitor_load_by_port(pPortName);
2459 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2460 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2461 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2462 TRACE("got %d with %u\n", res, GetLastError());
2463 }
2464 else
2465 {
2466 pui = monitor_loadui(pm);
2467 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2468 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2469 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2470 TRACE("got %d with %u\n", res, GetLastError());
2471 }
2472 else
2473 {
2474 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2475 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
2476
2477 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2478 SetLastError(ERROR_NOT_SUPPORTED);
2479 res = FALSE;
2480 }
2481 monitor_unload(pui);
2482 }
2483 monitor_unload(pm);
2484
2485 TRACE("returning %d with %u\n", res, GetLastError());
2486 return res;
2487 }
2488
2489 /******************************************************************************
2490 * SetPrinterW [WINSPOOL.@]
2491 */
2492 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2493 {
2494 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2495 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2496 return FALSE;
2497 }
2498
2499 /******************************************************************************
2500 * WritePrinter [WINSPOOL.@]
2501 */
2502 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2503 {
2504 opened_printer_t *printer;
2505 BOOL ret = FALSE;
2506
2507 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2508
2509 EnterCriticalSection(&printer_handles_cs);
2510 printer = get_opened_printer(hPrinter);
2511 if(!printer)
2512 {
2513 SetLastError(ERROR_INVALID_HANDLE);
2514 goto end;
2515 }
2516
2517 if(!printer->doc)
2518 {
2519 SetLastError(ERROR_SPL_NO_STARTDOC);
2520 goto end;
2521 }
2522
2523 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2524 end:
2525 LeaveCriticalSection(&printer_handles_cs);
2526 return ret;
2527 }
2528
2529 /*****************************************************************************
2530 * AddFormA [WINSPOOL.@]
2531 */
2532 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2533 {
2534 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2535 return 1;
2536 }
2537
2538 /*****************************************************************************
2539 * AddFormW [WINSPOOL.@]
2540 */
2541 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2542 {
2543 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2544 return 1;
2545 }
2546
2547 /*****************************************************************************
2548 * AddJobA [WINSPOOL.@]
2549 */
2550 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2551 {
2552 BOOL ret;
2553 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2554 DWORD needed;
2555
2556 if(Level != 1) {
2557 SetLastError(ERROR_INVALID_LEVEL);
2558 return FALSE;
2559 }
2560
2561 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2562
2563 if(ret) {
2564 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2565 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2566 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2567 if(*pcbNeeded > cbBuf) {
2568 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2569 ret = FALSE;
2570 } else {
2571 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2572 addjobA->JobId = addjobW->JobId;
2573 addjobA->Path = (char *)(addjobA + 1);
2574 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2575 }
2576 }
2577 return ret;
2578 }
2579
2580 /*****************************************************************************
2581 * AddJobW [WINSPOOL.@]
2582 */
2583 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2584 {
2585 opened_printer_t *printer;
2586 job_t *job;
2587 BOOL ret = FALSE;
2588 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2589 static const WCHAR fmtW[] = {'%','s','%','','5','d','.','S','P','L',0};
2590 WCHAR path[MAX_PATH], filename[MAX_PATH];
2591 DWORD len;
2592 ADDJOB_INFO_1W *addjob;
2593
2594 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2595
2596 EnterCriticalSection(&printer_handles_cs);
2597
2598 printer = get_opened_printer(hPrinter);
2599
2600 if(!printer) {
2601 SetLastError(ERROR_INVALID_HANDLE);
2602 goto end;
2603 }
2604
2605 if(Level != 1) {
2606 SetLastError(ERROR_INVALID_LEVEL);
2607 goto end;
2608 }
2609
2610 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2611 if(!job)
2612 goto end;
2613
2614 job->job_id = InterlockedIncrement(&next_job_id);
2615
2616 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2617 if(path[len - 1] != '\\')
2618 path[len++] = '\\';
2619 memcpy(path + len, spool_path, sizeof(spool_path));
2620 sprintfW(filename, fmtW, path, job->job_id);
2621
2622 len = strlenW(filename);
2623 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2624 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2625 job->document_title = strdupW(default_doc_title);
2626 list_add_tail(&printer->queue->jobs, &job->entry);
2627
2628 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2629 if(*pcbNeeded <= cbBuf) {
2630 addjob = (ADDJOB_INFO_1W*)pData;
2631 addjob->JobId = job->job_id;
2632 addjob->Path = (WCHAR *)(addjob + 1);
2633 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2634 ret = TRUE;
2635 } else
2636 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2637
2638 end:
2639 LeaveCriticalSection(&printer_handles_cs);
2640 return ret;
2641 }
2642
2643 /*****************************************************************************
2644 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2645 *
2646 * Return the PATH for the Print-Processors
2647 *
2648 * See GetPrintProcessorDirectoryW.
2649 *
2650 *
2651 */
2652 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2653 DWORD level, LPBYTE Info,
2654 DWORD cbBuf, LPDWORD pcbNeeded)
2655 {
2656 LPWSTR serverW = NULL;
2657 LPWSTR envW = NULL;
2658 BOOL ret;
2659 INT len;
2660
2661 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2662 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2663
2664
2665 if (server) {
2666 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2667 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2668 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2669 }
2670
2671 if (env) {
2672 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2673 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2674 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2675 }
2676
2677 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2678 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2679 */
2680 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2681 cbBuf, pcbNeeded);
2682
2683 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2684 cbBuf, NULL, NULL) > 0;
2685
2686
2687 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2688 HeapFree(GetProcessHeap(), 0, envW);
2689 HeapFree(GetProcessHeap(), 0, serverW);
2690 return ret;
2691 }
2692
2693 /*****************************************************************************
2694 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2695 *
2696 * Return the PATH for the Print-Processors
2697 *
2698 * PARAMS
2699 * server [I] Servername (NT only) or NULL (local Computer)
2700 * env [I] Printing-Environment (see below) or NULL (Default)
2701 * level [I] Structure-Level (must be 1)
2702 * Info [O] PTR to Buffer that receives the Result
2703 * cbBuf [I] Size of Buffer at "Info"
2704 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2705 * required for the Buffer at "Info"
2706 *
2707 * RETURNS
2708 * Success: TRUE and in pcbNeeded the Bytes used in Info
2709 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2710 * if cbBuf is too small
2711 *
2712 * Native Values returned in Info on Success:
2713 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2714 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2715 *| win9x(Windows 4.0): "%winsysdir%"
2716 *
2717 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2718 *
2719 * BUGS
2720 * Only NULL or "" is supported for server
2721 *
2722 */
2723 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2724 DWORD level, LPBYTE Info,
2725 DWORD cbBuf, LPDWORD pcbNeeded)
2726 {
2727 DWORD needed;
2728 const printenv_t * env_t;
2729
2730 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2731 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2732
2733 if(server != NULL && server[0]) {
2734 FIXME("server not supported: %s\n", debugstr_w(server));
2735 SetLastError(ERROR_INVALID_PARAMETER);
2736 return FALSE;
2737 }
2738
2739 env_t = validate_envW(env);
2740 if(!env_t) return FALSE; /* environment invalid or unsupported */
2741
2742 if(level != 1) {
2743 WARN("(Level: %d) is ignored in win9x\n", level);
2744 SetLastError(ERROR_INVALID_LEVEL);
2745 return FALSE;
2746 }
2747
2748 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2749 needed = GetSystemDirectoryW(NULL, 0);
2750 /* add the Size for the Subdirectories */
2751 needed += lstrlenW(spoolprtprocsW);
2752 needed += lstrlenW(env_t->subdir);
2753 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2754
2755 if(pcbNeeded) *pcbNeeded = needed;
2756 TRACE ("required: 0x%x/%d\n", needed, needed);
2757 if (needed > cbBuf) {
2758 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2759 return FALSE;
2760 }
2761 if(pcbNeeded == NULL) {
2762 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2763 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2764 SetLastError(RPC_X_NULL_REF_POINTER);
2765 return FALSE;
2766 }
2767 if(Info == NULL) {
2768 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2769 SetLastError(RPC_X_NULL_REF_POINTER);
2770 return FALSE;
2771 }
2772
2773 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2774 /* add the Subdirectories */
2775 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2776 lstrcatW((LPWSTR) Info, env_t->subdir);
2777 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2778 return TRUE;
2779 }
2780
2781 /*****************************************************************************
2782 * WINSPOOL_OpenDriverReg [internal]
2783 *
2784 * opens the registry for the printer drivers depending on the given input
2785 * variable pEnvironment
2786 *
2787 * RETURNS:
2788 * the opened hkey on success
2789 * NULL on error
2790 */
2791 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2792 {
2793 HKEY retval = NULL;
2794 LPWSTR buffer;
2795 const printenv_t * env;
2796
2797 TRACE("(%s, %d)\n",
2798 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2799
2800 if (!pEnvironment || unicode) {
2801 /* pEnvironment was NULL or a Unicode-String: use it direct */
2802 env = validate_envW(pEnvironment);
2803 }
2804 else
2805 {
2806 /* pEnvironment was an ANSI-String: convert to unicode first */
2807 LPWSTR buffer;
2808 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2809 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2810 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2811 env = validate_envW(buffer);
2812 HeapFree(GetProcessHeap(), 0, buffer);
2813 }
2814 if (!env) return NULL;
2815
2816 buffer = HeapAlloc( GetProcessHeap(), 0,
2817 (strlenW(DriversW) + strlenW(env->envname) +
2818 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2819 if(buffer) {
2820 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2821 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2822 HeapFree(GetProcessHeap(), 0, buffer);
2823 }
2824 return retval;
2825 }
2826
2827 /*****************************************************************************
2828 * AddPrinterW [WINSPOOL.@]
2829 */
2830 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2831 {
2832 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2833 LPDEVMODEA dmA;
2834 LPDEVMODEW dmW;
2835 HANDLE retval;
2836 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2837 LONG size;
2838 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2839 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2840 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2841 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2842 statusW[] = {'S','t','a','t','u','s',0},
2843 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2844
2845 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2846
2847 if(pName != NULL) {
2848 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2849 SetLastError(ERROR_INVALID_PARAMETER);
2850 return 0;
2851 }
2852 if(Level != 2) {
2853 ERR("Level = %d, unsupported!\n", Level);
2854 SetLastError(ERROR_INVALID_LEVEL);
2855 return 0;
2856 }
2857 if(!pPrinter) {
2858 SetLastError(ERROR_INVALID_PARAMETER);
2859 return 0;
2860 }
2861 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2862 ERROR_SUCCESS) {
2863 ERR("Can't create Printers key\n");
2864 return 0;
2865 }
2866 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2867 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2868 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2869 RegCloseKey(hkeyPrinter);
2870 RegCloseKey(hkeyPrinters);
2871 return 0;
2872 }
2873 RegCloseKey(hkeyPrinter);
2874 }
2875 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2876 if(!hkeyDrivers) {
2877 ERR("Can't create Drivers key\n");
2878 RegCloseKey(hkeyPrinters);
2879 return 0;
2880 }
2881 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2882 ERROR_SUCCESS) {
2883 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2884 RegCloseKey(hkeyPrinters);
2885 RegCloseKey(hkeyDrivers);
2886 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2887 return 0;
2888 }
2889 RegCloseKey(hkeyDriver);
2890 RegCloseKey(hkeyDrivers);
2891
2892 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2893 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2894 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2895 RegCloseKey(hkeyPrinters);
2896 return 0;
2897 }
2898
2899 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2900 ERROR_SUCCESS) {
2901 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2902 SetLastError(ERROR_INVALID_PRINTER_NAME);
2903 RegCloseKey(hkeyPrinters);
2904 return 0;
2905 }
2906 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2907 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2908 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2909
2910 /* See if we can load the driver. We may need the devmode structure anyway
2911 *
2912 * FIXME:
2913 * Note that DocumentPropertiesW will briefly try to open the printer we
2914 * just create to find a DEVMODEA struct (it will use the WINEPS default
2915 * one in case it is not there, so we are ok).
2916 */
2917 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2918
2919 if(size < 0) {
2920 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2921 size = sizeof(DEVMODEW);
2922 }
2923 if(pi->pDevMode)
2924 dmW = pi->pDevMode;
2925 else
2926 {
2927 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2928 dmW->dmSize = size;
2929 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2930 {
2931 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2932 HeapFree(GetProcessHeap(),0,dmW);
2933 dmW=NULL;
2934 }
2935 else
2936 {
2937 /* set devmode to printer name */
2938 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2939 }
2940 }
2941
2942 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2943 and we support these drivers. NT writes DEVMODEW so somehow
2944 we'll need to distinguish between these when we support NT
2945 drivers */
2946 if (dmW)
2947 {
2948 dmA = DEVMODEdupWtoA(dmW);
2949 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2950 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2951 HeapFree(GetProcessHeap(), 0, dmA);
2952 if(!pi->pDevMode)
2953 HeapFree(GetProcessHeap(), 0, dmW);
2954 }
2955 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2956 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2957 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2958 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2959
2960 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2961 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2962 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2963 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2964 (LPBYTE)&pi->Priority, sizeof(DWORD));
2965 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2966 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2967 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2968 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2969 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2970 (LPBYTE)&pi->Status, sizeof(DWORD));
2971 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2972 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2973
2974 RegCloseKey(hkeyPrinter);
2975 RegCloseKey(hkeyPrinters);
2976 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2977 ERR("OpenPrinter failing\n");
2978 return 0;
2979 }
2980 return retval;
2981 }
2982
2983 /*****************************************************************************
2984 * AddPrinterA [WINSPOOL.@]
2985 */
2986 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2987 {
2988 UNICODE_STRING pNameW;
2989 PWSTR pwstrNameW;
2990 PRINTER_INFO_2W *piW;
2991 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2992 HANDLE ret;
2993
2994 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2995 if(Level != 2) {
2996 ERR("Level = %d, unsupported!\n", Level);
2997 SetLastError(ERROR_INVALID_LEVEL);
2998 return 0;
2999 }
3000 pwstrNameW = asciitounicode(&pNameW,pName);
3001 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
3002
3003 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3004
3005 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
3006 RtlFreeUnicodeString(&pNameW);
3007 return ret;
3008 }
3009
3010
3011 /*****************************************************************************
3012 * ClosePrinter [WINSPOOL.@]
3013 */
3014 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3015 {
3016 UINT_PTR i = (UINT_PTR)hPrinter;
3017 opened_printer_t *printer = NULL;
3018 BOOL ret = FALSE;
3019
3020 TRACE("(%p)\n", hPrinter);
3021
3022 EnterCriticalSection(&printer_handles_cs);
3023
3024 if ((i > 0) && (i <= nb_printer_handles))
3025 printer = printer_handles[i - 1];
3026
3027
3028 if(printer)
3029 {
3030 struct list *cursor, *cursor2;
3031
3032 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer->pm,
3033 debugstr_w(printer->pm ? printer->pm->dllname : NULL),
3034 printer->hXcv, debugstr_w(printer->name), printer->doc );
3035
3036 if(printer->doc)
3037 EndDocPrinter(hPrinter);
3038
3039 if(InterlockedDecrement(&printer->queue->ref) == 0)
3040 {
3041 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3042 {
3043 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3044 ScheduleJob(hPrinter, job->job_id);
3045 }
3046 HeapFree(GetProcessHeap(), 0, printer->queue);
3047 }
3048 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
3049 monitor_unload(printer->pm);
3050 HeapFree(GetProcessHeap(), 0, printer->printername);
3051 HeapFree(GetProcessHeap(), 0, printer->name);
3052 HeapFree(GetProcessHeap(), 0, printer);
3053 printer_handles[i - 1] = NULL;
3054 ret = TRUE;
3055 }
3056 LeaveCriticalSection(&printer_handles_cs);
3057 return ret;
3058 }
3059
3060 /*****************************************************************************
3061 * DeleteFormA [WINSPOOL.@]
3062 */
3063 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3064 {
3065 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3066 return 1;
3067 }
3068
3069 /*****************************************************************************
3070 * DeleteFormW [WINSPOOL.@]
3071 */
3072 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3073 {
3074 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3075 return 1;
3076 }
3077
3078 /*****************************************************************************
3079 * DeletePrinter [WINSPOOL.@]
3080 */
3081 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3082 {
3083 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3084 HKEY hkeyPrinters, hkey;
3085
3086 if(!lpNameW) {
3087 SetLastError(ERROR_INVALID_HANDLE);
3088 return FALSE;
3089 }
3090 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3091 RegDeleteTreeW(hkeyPrinters, lpNameW);
3092 RegCloseKey(hkeyPrinters);
3093 }
3094 WriteProfileStringW(devicesW, lpNameW, NULL);
3095 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
3096
3097 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3098 RegDeleteValueW(hkey, lpNameW);
3099 RegCloseKey(hkey);
3100 }
3101
3102 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
3103 RegDeleteValueW(hkey, lpNameW);
3104 RegCloseKey(hkey);
3105 }
3106 return TRUE;
3107 }
3108
3109 /*****************************************************************************
3110 * SetPrinterA [WINSPOOL.@]
3111 */
3112 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3113 DWORD Command)
3114 {
3115 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
3116 return FALSE;
3117 }
3118
3119 /*****************************************************************************
3120 * SetJobA [WINSPOOL.@]
3121 */
3122 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3123 LPBYTE pJob, DWORD Command)
3124 {
3125 BOOL ret;
3126 LPBYTE JobW;
3127 UNICODE_STRING usBuffer;
3128
3129 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3130
3131 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3132 are all ignored by SetJob, so we don't bother copying them */
3133 switch(Level)
3134 {
3135 case 0:
3136 JobW = NULL;
3137 break;
3138 case 1:
3139 {
3140 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3141 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3142
3143 JobW = (LPBYTE)info1W;
3144 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3145 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3146 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3147 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3148 info1W->Status = info1A->Status;
3149 info1W->Priority = info1A->Priority;
3150 info1W->Position = info1A->Position;
3151 info1W->PagesPrinted = info1A->PagesPrinted;
3152 break;
3153 }
3154 case 2:
3155 {
3156 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3157 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3158
3159 JobW = (LPBYTE)info2W;
3160 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3161 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3162 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3163 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3164 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3165 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3166