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