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