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