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