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