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