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-2010 Detlef Riekenberg
10 * Copyright 2010 Vitaly Perov
11 *
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
16 *
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
21 *
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 */
26
27 #include "config.h"
28 #include "wine/port.h"
29
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <stddef.h>
36 #include <errno.h>
37 #ifdef HAVE_SYS_WAIT_H
38 #include <sys/wait.h>
39 #endif
40 #ifdef HAVE_UNISTD_H
41 # include <unistd.h>
42 #endif
43 #include <signal.h>
44 #ifdef HAVE_CUPS_CUPS_H
45 # include <cups/cups.h>
46 #endif
47
48 #define NONAMELESSUNION
49 #define NONAMELESSSTRUCT
50 #include "wine/library.h"
51 #include "windef.h"
52 #include "winbase.h"
53 #include "winuser.h"
54 #include "winerror.h"
55 #include "winreg.h"
56 #include "wingdi.h"
57 #include "winspool.h"
58 #include "winternl.h"
59 #include "wine/windef16.h"
60 #include "wine/unicode.h"
61 #include "wine/debug.h"
62 #include "wine/list.h"
63 #include "winnls.h"
64
65 #include "ddk/winsplp.h"
66 #include "wspool.h"
67
68 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
69
70 /* ############################### */
71
72 static CRITICAL_SECTION printer_handles_cs;
73 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
74 {
75 0, 0, &printer_handles_cs,
76 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
77 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
78 };
79 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
80
81 /* ############################### */
82
83 typedef struct {
84 DWORD job_id;
85 HANDLE hf;
86 } started_doc_t;
87
88 typedef struct {
89 struct list jobs;
90 LONG ref;
91 } jobqueue_t;
92
93 typedef struct {
94 LPWSTR name;
95 LPWSTR printername;
96 HANDLE backend_printer;
97 jobqueue_t *queue;
98 started_doc_t *doc;
99 DEVMODEW *devmode;
100 } opened_printer_t;
101
102 typedef struct {
103 struct list entry;
104 DWORD job_id;
105 WCHAR *filename;
106 WCHAR *portname;
107 WCHAR *document_title;
108 WCHAR *printer_name;
109 LPDEVMODEW devmode;
110 } job_t;
111
112
113 typedef struct {
114 LPCWSTR envname;
115 LPCWSTR subdir;
116 DWORD driverversion;
117 LPCWSTR versionregpath;
118 LPCWSTR versionsubdir;
119 } printenv_t;
120
121 /* ############################### */
122
123 static opened_printer_t **printer_handles;
124 static UINT nb_printer_handles;
125 static LONG next_job_id = 1;
126
127 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
128 WORD fwCapability, LPSTR lpszOutput,
129 LPDEVMODEA lpdm );
130 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
131 LPSTR lpszDevice, LPSTR lpszPort,
132 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
133 DWORD fwMode );
134
135 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
136 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
137 'c','o','n','t','r','o','l','\\',
138 'P','r','i','n','t','\\',
139 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
140 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
141
142 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
143 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
144 'C','o','n','t','r','o','l','\\',
145 'P','r','i','n','t','\\',
146 'P','r','i','n','t','e','r','s',0};
147
148 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
149
150 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
151 'M','i','c','r','o','s','o','f','t','\\',
152 'W','i','n','d','o','w','s',' ','N','T','\\',
153 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
154 'W','i','n','d','o','w','s',0};
155
156 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
157 'M','i','c','r','o','s','o','f','t','\\',
158 'W','i','n','d','o','w','s',' ','N','T','\\',
159 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
160 'D','e','v','i','c','e','s',0};
161
162 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
163 'M','i','c','r','o','s','o','f','t','\\',
164 'W','i','n','d','o','w','s',' ','N','T','\\',
165 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
166 'P','o','r','t','s',0};
167
168 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
169 'M','i','c','r','o','s','o','f','t','\\',
170 'W','i','n','d','o','w','s',' ','N','T','\\',
171 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
172 'P','r','i','n','t','e','r','P','o','r','t','s',0};
173
174 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
175 static WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','',0};
176 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
177 static WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
178 static const WCHAR subdir_win40W[] = {'w','i','n','4','',0};
179 static const WCHAR subdir_x64W[] = {'x','6','4',0};
180 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
181 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','',0};
182 static const WCHAR Version0_SubdirW[] = {'\\','',0};
183 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
184 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
185
186 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
187 static const WCHAR backslashW[] = {'\\',0};
188 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
189 'i','o','n',' ','F','i','l','e',0};
190 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
191 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
192 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
193 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
194 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
195 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
196 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
197 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
198 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
199 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
200 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
201 static const WCHAR NameW[] = {'N','a','m','e',0};
202 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
203 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
204 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
205 static const WCHAR PortW[] = {'P','o','r','t',0};
206 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
207 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
208 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
209 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
210 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
211 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
212 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
213 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
214 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
215 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
216 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
217 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
218 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
219 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
220 static WCHAR generic_ppdW[] = {'g','e','n','e','r','i','c','.','p','p','d',0};
221 static WCHAR rawW[] = {'R','A','W',0};
222 static WCHAR driver_9x[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
223 static WCHAR driver_nt[] = {'w','i','n','e','p','s','.','d','r','v',0};
224 static const WCHAR timeout_15_45[] = {',','1','5',',','4','5',0};
225 static const WCHAR commaW[] = {',',0};
226 static WCHAR emptyStringW[] = {0};
227
228 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
229
230 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
231 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
232 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
233
234 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
235 'D','o','c','u','m','e','n','t',0};
236
237 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
238 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
239 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
240 0, sizeof(DRIVER_INFO_8W)};
241
242
243 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
244 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
245 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
246 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
247 sizeof(PRINTER_INFO_9W)};
248
249 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
250 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
251 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
252
253 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
254
255 /******************************************************************
256 * validate the user-supplied printing-environment [internal]
257 *
258 * PARAMS
259 * env [I] PTR to Environment-String or NULL
260 *
261 * RETURNS
262 * Failure: NULL
263 * Success: PTR to printenv_t
264 *
265 * NOTES
266 * An empty string is handled the same way as NULL.
267 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
268 *
269 */
270
271 static const printenv_t * validate_envW(LPCWSTR env)
272 {
273 const printenv_t *result = NULL;
274 unsigned int i;
275
276 TRACE("testing %s\n", debugstr_w(env));
277 if (env && env[0])
278 {
279 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
280 {
281 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
282 {
283 result = all_printenv[i];
284 break;
285 }
286 }
287
288 if (result == NULL) {
289 FIXME("unsupported Environment: %s\n", debugstr_w(env));
290 SetLastError(ERROR_INVALID_ENVIRONMENT);
291 }
292 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
293 }
294 else
295 {
296 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
297 }
298 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
299
300 return result;
301 }
302
303
304 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
305 if passed a NULL string. This returns NULLs to the result.
306 */
307 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
308 {
309 if ( (src) )
310 {
311 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
312 return usBufferPtr->Buffer;
313 }
314 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
315 return NULL;
316 }
317
318 static LPWSTR strdupW(LPCWSTR p)
319 {
320 LPWSTR ret;
321 DWORD len;
322
323 if(!p) return NULL;
324 len = (strlenW(p) + 1) * sizeof(WCHAR);
325 ret = HeapAlloc(GetProcessHeap(), 0, len);
326 memcpy(ret, p, len);
327 return ret;
328 }
329
330 static LPSTR strdupWtoA( LPCWSTR str )
331 {
332 LPSTR ret;
333 INT len;
334
335 if (!str) return NULL;
336 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
337 ret = HeapAlloc( GetProcessHeap(), 0, len );
338 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
339 return ret;
340 }
341
342 static DEVMODEW *dup_devmode( const DEVMODEW *dm )
343 {
344 DEVMODEW *ret;
345
346 if (!dm) return NULL;
347 ret = HeapAlloc( GetProcessHeap(), 0, dm->dmSize + dm->dmDriverExtra );
348 if (ret) memcpy( ret, dm, dm->dmSize + dm->dmDriverExtra );
349 return ret;
350 }
351
352 /***********************************************************
353 * DEVMODEdupWtoA
354 * Creates an ansi copy of supplied devmode
355 */
356 static DEVMODEA *DEVMODEdupWtoA( const DEVMODEW *dmW )
357 {
358 LPDEVMODEA dmA;
359 DWORD size;
360
361 if (!dmW) return NULL;
362 size = dmW->dmSize - CCHDEVICENAME -
363 ((dmW->dmSize > FIELD_OFFSET( DEVMODEW, dmFormName )) ? CCHFORMNAME : 0);
364
365 dmA = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra );
366 if (!dmA) return NULL;
367
368 WideCharToMultiByte( CP_ACP, 0, dmW->dmDeviceName, -1,
369 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL );
370
371 if (FIELD_OFFSET( DEVMODEW, dmFormName ) >= dmW->dmSize)
372 {
373 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
374 dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
375 }
376 else
377 {
378 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
379 FIELD_OFFSET( DEVMODEW, dmFormName ) - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
380 WideCharToMultiByte( CP_ACP, 0, dmW->dmFormName, -1,
381 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL );
382
383 memcpy( &dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmLogPixels ) );
384 }
385
386 dmA->dmSize = size;
387 memcpy( (char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra );
388 return dmA;
389 }
390
391
392 /******************************************************************
393 * verify, that the filename is a local file
394 *
395 */
396 static inline BOOL is_local_file(LPWSTR name)
397 {
398 return (name[0] && (name[1] == ':') && (name[2] == '\\'));
399 }
400
401 /* ################################ */
402
403 static int multi_sz_lenA(const char *str)
404 {
405 const char *ptr = str;
406 if(!str) return 0;
407 do
408 {
409 ptr += lstrlenA(ptr) + 1;
410 } while(*ptr);
411
412 return ptr - str + 1;
413 }
414
415 static void
416 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
417 char qbuf[200];
418
419 /* If forcing, or no profile string entry for device yet, set the entry
420 *
421 * The always change entry if not WINEPS yet is discussable.
422 */
423 if (force ||
424 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
425 !strcmp(qbuf,"*") ||
426 !strstr(qbuf,"WINEPS.DRV")
427 ) {
428 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
429 HKEY hkey;
430
431 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
432 WriteProfileStringA("windows","device",buf);
433 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
434 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
435 RegCloseKey(hkey);
436 }
437 HeapFree(GetProcessHeap(),0,buf);
438 }
439 }
440
441 static BOOL add_printer_driver(WCHAR *name)
442 {
443 DRIVER_INFO_3W di3;
444
445 ZeroMemory(&di3, sizeof(DRIVER_INFO_3W));
446 di3.cVersion = 3;
447 di3.pName = name;
448 di3.pEnvironment = envname_x86W;
449 di3.pDriverPath = driver_nt;
450 di3.pDataFile = generic_ppdW;
451 di3.pConfigFile = driver_nt;
452 di3.pDefaultDataType = rawW;
453
454 if (AddPrinterDriverW(NULL, 3, (LPBYTE)&di3) ||
455 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
456 {
457 di3.cVersion = 0;
458 di3.pEnvironment = envname_win40W;
459 di3.pDriverPath = driver_9x;
460 di3.pConfigFile = driver_9x;
461 if (AddPrinterDriverW(NULL, 3, (LPBYTE)&di3) ||
462 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
463 {
464 return TRUE;
465 }
466 }
467 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3.pDriverPath), debugstr_w(di3.pEnvironment));
468 return FALSE;
469 }
470
471 #ifdef SONAME_LIBCUPS
472
473 static void *cupshandle;
474
475 #define CUPS_FUNCS \
476 DO_FUNC(cupsFreeDests); \
477 DO_FUNC(cupsFreeOptions); \
478 DO_FUNC(cupsGetDests); \
479 DO_FUNC(cupsGetPPD); \
480 DO_FUNC(cupsParseOptions); \
481 DO_FUNC(cupsPrintFile);
482
483 #define DO_FUNC(f) static typeof(f) *p##f
484 CUPS_FUNCS;
485 #undef DO_FUNC
486
487 static BOOL CUPS_LoadPrinters(void)
488 {
489 int i, nrofdests;
490 BOOL hadprinter = FALSE, haddefault = FALSE;
491 cups_dest_t *dests;
492 PRINTER_INFO_2W pi2;
493 WCHAR *port;
494 HKEY hkeyPrinter, hkeyPrinters;
495 char loaderror[256];
496 WCHAR nameW[MAX_PATH];
497 HANDLE added_printer;
498
499 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
500 if (!cupshandle) {
501 TRACE("%s\n", loaderror);
502 return FALSE;
503 }
504 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
505
506 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); if (!p##x) return FALSE;
507 CUPS_FUNCS;
508 #undef DO_FUNC
509
510 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
511 ERROR_SUCCESS) {
512 ERR("Can't create Printers key\n");
513 return FALSE;
514 }
515
516 nrofdests = pcupsGetDests(&dests);
517 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
518 for (i=0;i<nrofdests;i++) {
519 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
520
521 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
522 lstrcpyW(port, CUPS_Port);
523 lstrcatW(port, nameW);
524
525 TRACE("Printer %d: %s\n", i, debugstr_w(nameW));
526 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
527 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
528 and continue */
529 TRACE("Printer already exists\n");
530 /* overwrite old LPR:* port */
531 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
532 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
533 RegCloseKey(hkeyPrinter);
534 } else {
535 static WCHAR comment_cups[] = {'W','I','N','E','P','S',' ','P','r','i','n','t','e','r',
536 ' ','u','s','i','n','g',' ','C','U','P','S',0};
537
538 add_printer_driver(nameW);
539
540 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
541 pi2.pPrinterName = nameW;
542 pi2.pDatatype = rawW;
543 pi2.pPrintProcessor = WinPrintW;
544 pi2.pDriverName = nameW;
545 pi2.pComment = comment_cups;
546 pi2.pLocation = emptyStringW;
547 pi2.pPortName = port;
548 pi2.pParameters = emptyStringW;
549 pi2.pShareName = emptyStringW;
550 pi2.pSepFile = emptyStringW;
551
552 added_printer = AddPrinterW( NULL, 2, (LPBYTE)&pi2 );
553 if (added_printer) ClosePrinter( added_printer );
554 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
555 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError() );
556 }
557 HeapFree(GetProcessHeap(),0,port);
558
559 hadprinter = TRUE;
560 if (dests[i].is_default) {
561 SetDefaultPrinterW(nameW);
562 haddefault = TRUE;
563 }
564 }
565 if (hadprinter && !haddefault) {
566 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
567 SetDefaultPrinterW(nameW);
568 }
569 pcupsFreeDests(nrofdests, dests);
570 RegCloseKey(hkeyPrinters);
571 return TRUE;
572 }
573 #endif
574
575 static BOOL PRINTCAP_ParseEntry( const char *pent, BOOL isfirst )
576 {
577 PRINTER_INFO_2A pinfo2a;
578 const char *r;
579 size_t name_len;
580 char *e,*s,*name,*prettyname,*devname;
581 BOOL ret = FALSE, set_default = FALSE;
582 char *port = NULL, *env_default;
583 HKEY hkeyPrinter, hkeyPrinters;
584 WCHAR devnameW[MAX_PATH];
585 HANDLE added_printer;
586
587 while (isspace(*pent)) pent++;
588 r = strchr(pent,':');
589 if (r)
590 name_len = r - pent;
591 else
592 name_len = strlen(pent);
593 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
594 memcpy(name, pent, name_len);
595 name[name_len] = '\0';
596 if (r)
597 pent = r;
598 else
599 pent = "";
600
601 TRACE("name=%s entry=%s\n",name, pent);
602
603 if(ispunct(*name)) { /* a tc entry, not a real printer */
604 TRACE("skipping tc entry\n");
605 goto end;
606 }
607
608 if(strstr(pent,":server")) { /* server only version so skip */
609 TRACE("skipping server entry\n");
610 goto end;
611 }
612
613 /* Determine whether this is a postscript printer. */
614
615 ret = TRUE;
616 env_default = getenv("PRINTER");
617 prettyname = name;
618 /* Get longest name, usually the one at the right for later display. */
619 while((s=strchr(prettyname,'|'))) {
620 *s = '\0';
621 e = s;
622 while(isspace(*--e)) *e = '\0';
623 TRACE("\t%s\n", debugstr_a(prettyname));
624 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
625 for(prettyname = s+1; isspace(*prettyname); prettyname++)
626 ;
627 }
628 e = prettyname + strlen(prettyname);
629 while(isspace(*--e)) *e = '\0';
630 TRACE("\t%s\n", debugstr_a(prettyname));
631 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
632
633 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
634 * if it is too long, we use it as comment below. */
635 devname = prettyname;
636 if (strlen(devname)>=CCHDEVICENAME-1)
637 devname = name;
638 if (strlen(devname)>=CCHDEVICENAME-1) {
639 ret = FALSE;
640 goto end;
641 }
642
643 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
644 sprintf(port,"LPR:%s",name);
645
646 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
647 ERROR_SUCCESS) {
648 ERR("Can't create Printers key\n");
649 ret = FALSE;
650 goto end;
651 }
652
653 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
654
655 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
656 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
657 and continue */
658 TRACE("Printer already exists\n");
659 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
660 RegCloseKey(hkeyPrinter);
661 } else {
662 static CHAR data_type[] = "RAW",
663 print_proc[] = "WinPrint",
664 comment[] = "WINEPS Printer using LPR",
665 params[] = "<parameters?>",
666 share_name[] = "<share name?>",
667 sep_file[] = "<sep file?>";
668
669 add_printer_driver(devnameW);
670
671 memset(&pinfo2a,0,sizeof(pinfo2a));
672 pinfo2a.pPrinterName = devname;
673 pinfo2a.pDatatype = data_type;
674 pinfo2a.pPrintProcessor = print_proc;
675 pinfo2a.pDriverName = devname;
676 pinfo2a.pComment = comment;
677 pinfo2a.pLocation = prettyname;
678 pinfo2a.pPortName = port;
679 pinfo2a.pParameters = params;
680 pinfo2a.pShareName = share_name;
681 pinfo2a.pSepFile = sep_file;
682
683 added_printer = AddPrinterA( NULL, 2, (LPBYTE)&pinfo2a );
684 if (added_printer) ClosePrinter( added_printer );
685 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
686 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name), GetLastError() );
687 }
688 RegCloseKey(hkeyPrinters);
689
690 if (isfirst || set_default)
691 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
692
693 end:
694 HeapFree(GetProcessHeap(), 0, port);
695 HeapFree(GetProcessHeap(), 0, name);
696 return ret;
697 }
698
699 static BOOL
700 PRINTCAP_LoadPrinters(void) {
701 BOOL hadprinter = FALSE;
702 char buf[200];
703 FILE *f;
704 char *pent = NULL;
705 BOOL had_bash = FALSE;
706
707 f = fopen("/etc/printcap","r");
708 if (!f)
709 return FALSE;
710
711 while(fgets(buf,sizeof(buf),f)) {
712 char *start, *end;
713
714 end=strchr(buf,'\n');
715 if (end) *end='\0';
716
717 start = buf;
718 while(isspace(*start)) start++;
719 if(*start == '#' || *start == '\0')
720 continue;
721
722 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
723 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
724 HeapFree(GetProcessHeap(),0,pent);
725 pent = NULL;
726 }
727
728 if (end && *--end == '\\') {
729 *end = '\0';
730 had_bash = TRUE;
731 } else
732 had_bash = FALSE;
733
734 if (pent) {
735 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
736 strcat(pent,start);
737 } else {
738 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
739 strcpy(pent,start);
740 }
741
742 }
743 if(pent) {
744 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
745 HeapFree(GetProcessHeap(),0,pent);
746 }
747 fclose(f);
748 return hadprinter;
749 }
750
751 static inline DWORD set_reg_DWORD(HKEY hkey, LPCSTR keyname, const DWORD value)
752 {
753 return RegSetValueExA(hkey, keyname, 0, REG_DWORD, (const BYTE*)&value, sizeof(value));
754 }
755
756 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
757 {
758 if (value)
759 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
760 (lstrlenW(value) + 1) * sizeof(WCHAR));
761 else
762 return ERROR_FILE_NOT_FOUND;
763 }
764
765 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
766 {
767 DEVMODEA *dmA = DEVMODEdupWtoA( dm );
768 DWORD ret = ERROR_FILE_NOT_FOUND;
769
770 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
771 and we support these drivers. NT writes DEVMODEW so somehow
772 we'll need to distinguish between these when we support NT
773 drivers */
774
775 if (dmA)
776 {
777 ret = RegSetValueExW( key, name, 0, REG_BINARY,
778 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
779 HeapFree( GetProcessHeap(), 0, dmA );
780 }
781
782 return ret;
783 }
784
785 /******************************************************************
786 * get_servername_from_name (internal)
787 *
788 * for an external server, a copy of the serverpart from the full name is returned
789 *
790 */
791 static LPWSTR get_servername_from_name(LPCWSTR name)
792 {
793 LPWSTR server;
794 LPWSTR ptr;
795 WCHAR buffer[MAX_PATH];
796 DWORD len;
797
798 if (name == NULL) return NULL;
799 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
800
801 server = strdupW(&name[2]); /* skip over both backslash */
802 if (server == NULL) return NULL;
803
804 /* strip '\' and the printername */
805 ptr = strchrW(server, '\\');
806 if (ptr) ptr[0] = '\0';
807
808 TRACE("found %s\n", debugstr_w(server));
809
810 len = sizeof(buffer)/sizeof(buffer[0]);
811 if (GetComputerNameW(buffer, &len)) {
812 if (lstrcmpW(buffer, server) == 0) {
813 /* The requested Servername is our computername */
814 HeapFree(GetProcessHeap(), 0, server);
815 return NULL;
816 }
817 }
818 return server;
819 }
820
821 /******************************************************************
822 * get_basename_from_name (internal)
823 *
824 * skip over the serverpart from the full name
825 *
826 */
827 static LPCWSTR get_basename_from_name(LPCWSTR name)
828 {
829 if (name == NULL) return NULL;
830 if ((name[0] == '\\') && (name[1] == '\\')) {
831 /* skip over the servername and search for the following '\' */
832 name = strchrW(&name[2], '\\');
833 if ((name) && (name[1])) {
834 /* found a separator ('\') followed by a name:
835 skip over the separator and return the rest */
836 name++;
837 }
838 else
839 {
840 /* no basename present (we found only a servername) */
841 return NULL;
842 }
843 }
844 return name;
845 }
846
847 static void free_printer_entry( opened_printer_t *printer )
848 {
849 /* the queue is shared, so don't free that here */
850 HeapFree( GetProcessHeap(), 0, printer->printername );
851 HeapFree( GetProcessHeap(), 0, printer->name );
852 HeapFree( GetProcessHeap(), 0, printer->devmode );
853 HeapFree( GetProcessHeap(), 0, printer );
854 }
855
856 /******************************************************************
857 * get_opened_printer_entry
858 * Get the first place empty in the opened printer table
859 *
860 * ToDo:
861 * - pDefault is ignored
862 */
863 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
864 {
865 UINT_PTR handle = nb_printer_handles, i;
866 jobqueue_t *queue = NULL;
867 opened_printer_t *printer = NULL;
868 LPWSTR servername;
869 LPCWSTR printername;
870
871 if ((backend == NULL) && !load_backend()) return NULL;
872
873 servername = get_servername_from_name(name);
874 if (servername) {
875 FIXME("server %s not supported\n", debugstr_w(servername));
876 HeapFree(GetProcessHeap(), 0, servername);
877 SetLastError(ERROR_INVALID_PRINTER_NAME);
878 return NULL;
879 }
880
881 printername = get_basename_from_name(name);
882 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
883
884 /* an empty printername is invalid */
885 if (printername && (!printername[0])) {
886 SetLastError(ERROR_INVALID_PARAMETER);
887 return NULL;
888 }
889
890 EnterCriticalSection(&printer_handles_cs);
891
892 for (i = 0; i < nb_printer_handles; i++)
893 {
894 if (!printer_handles[i])
895 {
896 if(handle == nb_printer_handles)
897 handle = i;
898 }
899 else
900 {
901 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
902 queue = printer_handles[i]->queue;
903 }
904 }
905
906 if (handle >= nb_printer_handles)
907 {
908 opened_printer_t **new_array;
909 if (printer_handles)
910 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
911 (nb_printer_handles + 16) * sizeof(*new_array) );
912 else
913 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
914 (nb_printer_handles + 16) * sizeof(*new_array) );
915
916 if (!new_array)
917 {
918 handle = 0;
919 goto end;
920 }
921 printer_handles = new_array;
922 nb_printer_handles += 16;
923 }
924
925 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
926 {
927 handle = 0;
928 goto end;
929 }
930
931 /* get a printer handle from the backend */
932 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
933 handle = 0;
934 goto end;
935 }
936
937 /* clone the base name. This is NULL for the printserver */
938 printer->printername = strdupW(printername);
939
940 /* clone the full name */
941 printer->name = strdupW(name);
942 if (name && (!printer->name)) {
943 handle = 0;
944 goto end;
945 }
946
947 if (pDefault && pDefault->pDevMode)
948 printer->devmode = dup_devmode( pDefault->pDevMode );
949
950 if(queue)
951 printer->queue = queue;
952 else
953 {
954 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
955 if (!printer->queue) {
956 handle = 0;
957 goto end;
958 }
959 list_init(&printer->queue->jobs);
960 printer->queue->ref = 0;
961 }
962 InterlockedIncrement(&printer->queue->ref);
963
964 printer_handles[handle] = printer;
965 handle++;
966 end:
967 LeaveCriticalSection(&printer_handles_cs);
968 if (!handle && printer) {
969 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
970 free_printer_entry( printer );
971 }
972
973 return (HANDLE)handle;
974 }
975
976 /******************************************************************
977 * get_opened_printer
978 * Get the pointer to the opened printer referred by the handle
979 */
980 static opened_printer_t *get_opened_printer(HANDLE hprn)
981 {
982 UINT_PTR idx = (UINT_PTR)hprn;
983 opened_printer_t *ret = NULL;
984
985 EnterCriticalSection(&printer_handles_cs);
986
987 if ((idx > 0) && (idx <= nb_printer_handles)) {
988 ret = printer_handles[idx - 1];
989 }
990 LeaveCriticalSection(&printer_handles_cs);
991 return ret;
992 }
993
994 /******************************************************************
995 * get_opened_printer_name
996 * Get the pointer to the opened printer name referred by the handle
997 */
998 static LPCWSTR get_opened_printer_name(HANDLE hprn)
999 {
1000 opened_printer_t *printer = get_opened_printer(hprn);
1001 if(!printer) return NULL;
1002 return printer->name;
1003 }
1004
1005 static DWORD open_printer_reg_key( const WCHAR *name, HKEY *key )
1006 {
1007 HKEY printers;
1008 DWORD err;
1009
1010 *key = NULL;
1011 err = RegCreateKeyW( HKEY_LOCAL_MACHINE, PrintersW, &printers );
1012 if (err) return err;
1013
1014 err = RegOpenKeyW( printers, name, key );
1015 if (err) err = ERROR_INVALID_PRINTER_NAME;
1016 RegCloseKey( printers );
1017 return err;
1018 }
1019
1020 /******************************************************************
1021 * WINSPOOL_GetOpenedPrinterRegKey
1022 *
1023 */
1024 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1025 {
1026 LPCWSTR name = get_opened_printer_name(hPrinter);
1027
1028 if(!name) return ERROR_INVALID_HANDLE;
1029 return open_printer_reg_key( name, phkey );
1030 }
1031
1032 static void old_printer_check( BOOL delete_phase )
1033 {
1034 PRINTER_INFO_5W* pi;
1035 DWORD needed, type, num, delete, i, size;
1036 const DWORD one = 1;
1037 HKEY key;
1038 HANDLE hprn;
1039
1040 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1041 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1042
1043 pi = HeapAlloc( GetProcessHeap(), 0, needed );
1044 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1045 for (i = 0; i < num; i++)
1046 {
1047 if (strncmpW( pi[i].pPortName, CUPS_Port, strlenW(CUPS_Port) ) &&
1048 strncmpW( pi[i].pPortName, LPR_Port, strlenW(LPR_Port) ))
1049 continue;
1050
1051 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1052
1053 if (!delete_phase)
1054 {
1055 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1056 RegCloseKey( key );
1057 }
1058 else
1059 {
1060 delete = 0;
1061 size = sizeof( delete );
1062 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1063 RegCloseKey( key );
1064 if (delete)
1065 {
1066 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1067 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1068 {
1069 DeletePrinter( hprn );
1070 ClosePrinter( hprn );
1071 }
1072 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1073 }
1074 }
1075 }
1076 HeapFree(GetProcessHeap(), 0, pi);
1077 }
1078
1079 void WINSPOOL_LoadSystemPrinters(void)
1080 {
1081 HKEY hkey, hkeyPrinters;
1082 DWORD needed, num, i;
1083 WCHAR PrinterName[256];
1084 BOOL done = FALSE;
1085
1086 /* This ensures that all printer entries have a valid Name value. If causes
1087 problems later if they don't. If one is found to be missed we create one
1088 and set it equal to the name of the key */
1089 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1090 if(RegQueryInfoKeyW(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1091 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1092 for(i = 0; i < num; i++) {
1093 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1094 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1095 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1096 set_reg_szW(hkey, NameW, PrinterName);
1097 }
1098 RegCloseKey(hkey);
1099 }
1100 }
1101 }
1102 }
1103 RegCloseKey(hkeyPrinters);
1104 }
1105
1106 old_printer_check( FALSE );
1107
1108 #ifdef SONAME_LIBCUPS
1109 done = CUPS_LoadPrinters();
1110 #endif
1111
1112 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1113 PRINTCAP_LoadPrinters();
1114
1115 old_printer_check( TRUE );
1116
1117 return;
1118 }
1119
1120 /******************************************************************
1121 * get_job
1122 *
1123 * Get the pointer to the specified job.
1124 * Should hold the printer_handles_cs before calling.
1125 */
1126 static job_t *get_job(HANDLE hprn, DWORD JobId)
1127 {
1128 opened_printer_t *printer = get_opened_printer(hprn);
1129 job_t *job;
1130
1131 if(!printer) return NULL;
1132 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1133 {
1134 if(job->job_id == JobId)
1135 return job;
1136 }
1137 return NULL;
1138 }
1139
1140 /***********************************************************
1141 * DEVMODEcpyAtoW
1142 */
1143 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1144 {
1145 BOOL Formname;
1146 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1147 DWORD size;
1148
1149 Formname = (dmA->dmSize > off_formname);
1150 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1151 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1152 dmW->dmDeviceName, CCHDEVICENAME);
1153 if(!Formname) {
1154 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1155 dmA->dmSize - CCHDEVICENAME);
1156 } else {
1157 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1158 off_formname - CCHDEVICENAME);
1159 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1160 dmW->dmFormName, CCHFORMNAME);
1161 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1162 (off_formname + CCHFORMNAME));
1163 }
1164 dmW->dmSize = size;
1165 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1166 dmA->dmDriverExtra);
1167 return dmW;
1168 }
1169
1170 /******************************************************************
1171 * convert_printerinfo_W_to_A [internal]
1172 *
1173 */
1174 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1175 DWORD level, DWORD outlen, DWORD numentries)
1176 {
1177 DWORD id = 0;
1178 LPSTR ptr;
1179 INT len;
1180
1181 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1182
1183 len = pi_sizeof[level] * numentries;
1184 ptr = (LPSTR) out + len;
1185 outlen -= len;
1186
1187 /* copy the numbers of all PRINTER_INFO_* first */
1188 memcpy(out, pPrintersW, len);
1189
1190 while (id < numentries) {
1191 switch (level) {
1192 case 1:
1193 {
1194 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1195 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1196
1197 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1198 if (piW->pDescription) {
1199 piA->pDescription = ptr;
1200 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1201 ptr, outlen, NULL, NULL);
1202 ptr += len;
1203 outlen -= len;
1204 }
1205 if (piW->pName) {
1206 piA->pName = ptr;
1207 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1208 ptr, outlen, NULL, NULL);
1209 ptr += len;
1210 outlen -= len;
1211 }
1212 if (piW->pComment) {
1213 piA->pComment = ptr;
1214 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1215 ptr, outlen, NULL, NULL);
1216 ptr += len;
1217 outlen -= len;
1218 }
1219 break;
1220 }
1221
1222 case 2:
1223 {
1224 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1225 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1226 LPDEVMODEA dmA;
1227
1228 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1229 if (piW->pServerName) {
1230 piA->pServerName = ptr;
1231 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1232 ptr, outlen, NULL, NULL);
1233 ptr += len;
1234 outlen -= len;
1235 }
1236 if (piW->pPrinterName) {
1237 piA->pPrinterName = ptr;
1238 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1239 ptr, outlen, NULL, NULL);
1240 ptr += len;
1241 outlen -= len;
1242 }
1243 if (piW->pShareName) {
1244 piA->pShareName = ptr;
1245 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1246 ptr, outlen, NULL, NULL);
1247 ptr += len;
1248 outlen -= len;
1249 }
1250 if (piW->pPortName) {
1251 piA->pPortName = ptr;
1252 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1253 ptr, outlen, NULL, NULL);
1254 ptr += len;
1255 outlen -= len;
1256 }
1257 if (piW->pDriverName) {
1258 piA->pDriverName = ptr;
1259 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1260 ptr, outlen, NULL, NULL);
1261 ptr += len;
1262 outlen -= len;
1263 }
1264 if (piW->pComment) {
1265 piA->pComment = ptr;
1266 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1267 ptr, outlen, NULL, NULL);
1268 ptr += len;
1269 outlen -= len;
1270 }
1271 if (piW->pLocation) {
1272 piA->pLocation = ptr;
1273 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1274 ptr, outlen, NULL, NULL);
1275 ptr += len;
1276 outlen -= len;
1277 }
1278
1279 dmA = DEVMODEdupWtoA(piW->pDevMode);
1280 if (dmA) {
1281 /* align DEVMODEA to a DWORD boundary */
1282 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1283 ptr += len;
1284 outlen -= len;
1285
1286 piA->pDevMode = (LPDEVMODEA) ptr;
1287 len = dmA->dmSize + dmA->dmDriverExtra;
1288 memcpy(ptr, dmA, len);
1289 HeapFree(GetProcessHeap(), 0, dmA);
1290
1291 ptr += len;
1292 outlen -= len;
1293 }
1294
1295 if (piW->pSepFile) {
1296 piA->pSepFile = ptr;
1297 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1298 ptr, outlen, NULL, NULL);
1299 ptr += len;
1300 outlen -= len;
1301 }
1302 if (piW->pPrintProcessor) {
1303 piA->pPrintProcessor = ptr;
1304 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1305 ptr, outlen, NULL, NULL);
1306 ptr += len;
1307 outlen -= len;
1308 }
1309 if (piW->pDatatype) {
1310 piA->pDatatype = ptr;
1311 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1312 ptr, outlen, NULL, NULL);
1313 ptr += len;
1314 outlen -= len;
1315 }
1316 if (piW->pParameters) {
1317 piA->pParameters = ptr;
1318 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1319 ptr, outlen, NULL, NULL);
1320 ptr += len;
1321 outlen -= len;
1322 }
1323 if (piW->pSecurityDescriptor) {
1324 piA->pSecurityDescriptor = NULL;
1325 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1326 }
1327 break;
1328 }
1329
1330 case 4:
1331 {
1332 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1333 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1334
1335 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1336
1337 if (piW->pPrinterName) {
1338 piA->pPrinterName = ptr;
1339 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1340 ptr, outlen, NULL, NULL);
1341 ptr += len;
1342 outlen -= len;
1343 }
1344 if (piW->pServerName) {
1345 piA->pServerName = ptr;
1346 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1347 ptr, outlen, NULL, NULL);
1348 ptr += len;
1349 outlen -= len;
1350 }
1351 break;
1352 }
1353
1354 case 5:
1355 {
1356 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1357 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1358
1359 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1360
1361 if (piW->pPrinterName) {
1362 piA->pPrinterName = ptr;
1363 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1364 ptr, outlen, NULL, NULL);
1365 ptr += len;
1366 outlen -= len;
1367 }
1368 if (piW->pPortName) {
1369 piA->pPortName = ptr;
1370 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1371 ptr, outlen, NULL, NULL);
1372 ptr += len;
1373 outlen -= len;
1374 }
1375 break;
1376 }
1377
1378 case 6: /* 6A and 6W are the same structure */
1379 break;
1380
1381 case 7:
1382 {
1383 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1384 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1385
1386 TRACE("(%u) #%u\n", level, id);
1387 if (piW->pszObjectGUID) {
1388 piA->pszObjectGUID = ptr;
1389 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1390 ptr, outlen, NULL, NULL);
1391 ptr += len;
1392 outlen -= len;
1393 }
1394 break;
1395 }
1396
1397 case 8:
1398 case 9:
1399 {
1400 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1401 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1402 LPDEVMODEA dmA;
1403
1404 TRACE("(%u) #%u\n", level, id);
1405 dmA = DEVMODEdupWtoA(piW->pDevMode);
1406 if (dmA) {
1407 /* align DEVMODEA to a DWORD boundary */
1408 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1409 ptr += len;
1410 outlen -= len;
1411
1412 piA->pDevMode = (LPDEVMODEA) ptr;
1413 len = dmA->dmSize + dmA->dmDriverExtra;
1414 memcpy(ptr, dmA, len);
1415 HeapFree(GetProcessHeap(), 0, dmA);
1416
1417 ptr += len;
1418 outlen -= len;
1419 }
1420
1421 break;
1422 }
1423
1424 default:
1425 FIXME("for level %u\n", level);
1426 }
1427 pPrintersW += pi_sizeof[level];
1428 out += pi_sizeof[level];
1429 id++;
1430 }
1431 }
1432
1433 /******************************************************************
1434 * convert_driverinfo_W_to_A [internal]
1435 *
1436 */
1437 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1438 DWORD level, DWORD outlen, DWORD numentries)
1439 {
1440 DWORD id = 0;
1441 LPSTR ptr;
1442 INT len;
1443
1444 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1445
1446 len = di_sizeof[level] * numentries;
1447 ptr = (LPSTR) out + len;
1448 outlen -= len;
1449
1450 /* copy the numbers of all PRINTER_INFO_* first */
1451 memcpy(out, pDriversW, len);
1452
1453 #define COPY_STRING(fld) \
1454 { if (diW->fld){ \
1455 diA->fld = ptr; \
1456 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1457 ptr += len; outlen -= len;\
1458 }}
1459 #define COPY_MULTIZ_STRING(fld) \
1460 { LPWSTR p = diW->fld; if (p){ \
1461 diA->fld = ptr; \
1462 do {\
1463 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1464 ptr += len; outlen -= len; p += len;\
1465 }\
1466 while(len > 1 && outlen > 0); \
1467 }}
1468
1469 while (id < numentries)
1470 {
1471 switch (level)
1472 {
1473 case 1:
1474 {
1475 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1476 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1477
1478 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1479
1480 COPY_STRING(pName);
1481 break;
1482 }
1483 case 2:
1484 {
1485 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1486 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1487
1488 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1489
1490 COPY_STRING(pName);
1491 COPY_STRING(pEnvironment);
1492 COPY_STRING(pDriverPath);
1493 COPY_STRING(pDataFile);
1494 COPY_STRING(pConfigFile);
1495 break;
1496 }
1497 case 3:
1498 {
1499 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1500 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1501
1502 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1503
1504 COPY_STRING(pName);
1505 COPY_STRING(pEnvironment);
1506 COPY_STRING(pDriverPath);
1507 COPY_STRING(pDataFile);
1508 COPY_STRING(pConfigFile);
1509 COPY_STRING(pHelpFile);
1510 COPY_MULTIZ_STRING(pDependentFiles);
1511 COPY_STRING(pMonitorName);
1512 COPY_STRING(pDefaultDataType);
1513 break;
1514 }
1515 case 4:
1516 {
1517 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
1518 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
1519
1520 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1521
1522 COPY_STRING(pName);
1523 COPY_STRING(pEnvironment);
1524 COPY_STRING(pDriverPath);
1525 COPY_STRING(pDataFile);
1526 COPY_STRING(pConfigFile);
1527 COPY_STRING(pHelpFile);
1528 COPY_MULTIZ_STRING(pDependentFiles);
1529 COPY_STRING(pMonitorName);
1530 COPY_STRING(pDefaultDataType);
1531 COPY_MULTIZ_STRING(pszzPreviousNames);
1532 break;
1533 }
1534 case 5:
1535 {
1536 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
1537 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
1538
1539 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1540
1541 COPY_STRING(pName);
1542 COPY_STRING(pEnvironment);
1543 COPY_STRING(pDriverPath);
1544 COPY_STRING(pDataFile);
1545 COPY_STRING(pConfigFile);
1546 break;
1547 }
1548 case 6:
1549 {
1550 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
1551 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
1552
1553 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1554
1555 COPY_STRING(pName);
1556 COPY_STRING(pEnvironment);
1557 COPY_STRING(pDriverPath);
1558 COPY_STRING(pDataFile);
1559 COPY_STRING(pConfigFile);
1560 COPY_STRING(pHelpFile);
1561 COPY_MULTIZ_STRING(pDependentFiles);
1562 COPY_STRING(pMonitorName);
1563 COPY_STRING(pDefaultDataType);
1564 COPY_MULTIZ_STRING(pszzPreviousNames);
1565 COPY_STRING(pszMfgName);
1566 COPY_STRING(pszOEMUrl);
1567 COPY_STRING(pszHardwareID);
1568 COPY_STRING(pszProvider);
1569 break;
1570 }
1571 case 8:
1572 {
1573 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
1574 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
1575
1576 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1577
1578 COPY_STRING(pName);
1579 COPY_STRING(pEnvironment);
1580 COPY_STRING(pDriverPath);
1581 COPY_STRING(pDataFile);
1582 COPY_STRING(pConfigFile);
1583 COPY_STRING(pHelpFile);
1584 COPY_MULTIZ_STRING(pDependentFiles);
1585 COPY_STRING(pMonitorName);
1586 COPY_STRING(pDefaultDataType);
1587 COPY_MULTIZ_STRING(pszzPreviousNames);
1588 COPY_STRING(pszMfgName);
1589 COPY_STRING(pszOEMUrl);
1590 COPY_STRING(pszHardwareID);
1591 COPY_STRING(pszProvider);
1592 COPY_STRING(pszPrintProcessor);
1593 COPY_STRING(pszVendorSetup);
1594 COPY_MULTIZ_STRING(pszzColorProfiles);
1595 COPY_STRING(pszInfPath);
1596 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
1597 break;
1598 }
1599
1600
1601 default:
1602 FIXME("for level %u\n", level);
1603 }
1604
1605 pDriversW += di_sizeof[level];
1606 out += di_sizeof[level];
1607 id++;
1608
1609 }
1610 #undef COPY_STRING
1611 #undef COPY_MULTIZ_STRING
1612 }
1613
1614
1615 /***********************************************************
1616 * printer_info_AtoW
1617 */
1618 static void *printer_info_AtoW( const void *data, DWORD level )
1619 {
1620 void *ret;
1621 UNICODE_STRING usBuffer;
1622
1623 if (!data) return NULL;
1624
1625 if (level < 1 || level > 9) return NULL;
1626
1627 ret = HeapAlloc( GetProcessHeap(), 0, pi_sizeof[level] );
1628 if (!ret) return NULL;
1629
1630 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
1631
1632 switch (level)
1633 {
1634 case 2:
1635 {
1636 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
1637 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
1638
1639 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
1640 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
1641 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
1642 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
1643 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
1644 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
1645 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
1646 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
1647 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
1648 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
1649 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
1650 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
1651 break;
1652 }
1653
1654 case 8:
1655 case 9:
1656 {
1657 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
1658 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
1659
1660 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
1661 break;
1662 }
1663
1664 default:
1665 FIXME( "Unhandled level %d\n", level );
1666 HeapFree( GetProcessHeap(), 0, ret );
1667 return NULL;
1668 }
1669
1670 return ret;
1671 }
1672
1673 /***********************************************************
1674 * free_printer_info
1675 */
1676 static void free_printer_info( void *data, DWORD level )
1677 {
1678 if (!data) return;
1679
1680 switch (level)
1681 {
1682 case 2:
1683 {
1684 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
1685
1686 HeapFree( GetProcessHeap(), 0, piW->pServerName );
1687 HeapFree( GetProcessHeap(), 0, piW->pPrinterName );
1688 HeapFree( GetProcessHeap(), 0, piW->pShareName );
1689 HeapFree( GetProcessHeap(), 0, piW->pPortName );
1690 HeapFree( GetProcessHeap(), 0, piW->pDriverName );
1691 HeapFree( GetProcessHeap(), 0, piW->pComment );
1692 HeapFree( GetProcessHeap(), 0, piW->pLocation );
1693 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
1694 HeapFree( GetProcessHeap(), 0, piW->pSepFile );
1695 HeapFree( GetProcessHeap(), 0, piW->pPrintProcessor );
1696 HeapFree( GetProcessHeap(), 0, piW->pDatatype );
1697 HeapFree( GetProcessHeap(), 0, piW->pParameters );
1698 break;
1699 }
1700
1701 case 8:
1702 case 9:
1703 {
1704 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
1705
1706 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
1707 break;
1708 }
1709
1710 default:
1711 FIXME( "Unhandled level %d\n", level );
1712 }
1713
1714 HeapFree( GetProcessHeap(), 0, data );
1715 return;
1716 }
1717
1718 /******************************************************************
1719 * DeviceCapabilities [WINSPOOL.@]
1720 * DeviceCapabilitiesA [WINSPOOL.@]
1721 *
1722 */
1723 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1724 LPSTR pOutput, LPDEVMODEA lpdm)
1725 {
1726 INT ret;
1727
1728 if (!GDI_CallDeviceCapabilities16)
1729 {
1730 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1731 (LPCSTR)104 );
1732 if (!GDI_CallDeviceCapabilities16) return -1;
1733 }
1734 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1735
1736 /* If DC_PAPERSIZE map POINT16s to POINTs */
1737 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1738 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1739 POINT *pt = (POINT *)pOutput;
1740 INT i;
1741 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1742 for(i = 0; i < ret; i++, pt++)
1743 {
1744 pt->x = tmp[i].x;
1745 pt->y = tmp[i].y;
1746 }
1747 HeapFree( GetProcessHeap(), 0, tmp );
1748 }
1749 return ret;
1750 }
1751
1752
1753 /*****************************************************************************
1754 * DeviceCapabilitiesW [WINSPOOL.@]
1755 *
1756 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1757 *
1758 */
1759 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1760 WORD fwCapability, LPWSTR pOutput,
1761 const DEVMODEW *pDevMode)
1762 {
1763 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1764 LPSTR pDeviceA = strdupWtoA(pDevice);
1765 LPSTR pPortA = strdupWtoA(pPort);
1766 INT ret;
1767
1768 if(pOutput && (fwCapability == DC_BINNAMES ||
1769 fwCapability == DC_FILEDEPENDENCIES ||
1770 fwCapability == DC_PAPERNAMES)) {
1771 /* These need A -> W translation */
1772 INT size = 0, i;
1773 LPSTR pOutputA;
1774 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1775 dmA);
1776 if(ret == -1)
1777 return ret;
1778 switch(fwCapability) {
1779 case DC_BINNAMES:
1780 size = 24;
1781 break;
1782 case DC_PAPERNAMES:
1783 case DC_FILEDEPENDENCIES:
1784 size = 64;
1785 break;
1786 }
1787 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1788 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1789 dmA);
1790 for(i = 0; i < ret; i++)
1791 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1792 pOutput + (i * size), size);
1793 HeapFree(GetProcessHeap(), 0, pOutputA);
1794 } else {
1795 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1796 (LPSTR)pOutput, dmA);
1797 }
1798 HeapFree(GetProcessHeap(),0,pPortA);
1799 HeapFree(GetProcessHeap(),0,pDeviceA);
1800 HeapFree(GetProcessHeap(),0,dmA);
1801 return ret;
1802 }
1803
1804 /******************************************************************
1805 * DocumentPropertiesA [WINSPOOL.@]
1806 *
1807 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1808 */
1809 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1810 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1811 LPDEVMODEA pDevModeInput,DWORD fMode )
1812 {
1813 LPSTR lpName = pDeviceName;
1814 static CHAR port[] = "LPT1:";
1815 LONG ret;
1816
1817 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1818 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1819 );
1820
1821 if(!pDeviceName) {
1822 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1823 if(!lpNameW) {
1824 ERR("no name from hPrinter?\n");
1825 SetLastError(ERROR_INVALID_HANDLE);
1826 return -1;
1827 }
1828 lpName = strdupWtoA(lpNameW);
1829 }
1830
1831 if (!GDI_CallExtDeviceMode16)
1832 {
1833 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1834 (LPCSTR)102 );
1835 if (!GDI_CallExtDeviceMode16) {
1836 ERR("No CallExtDeviceMode16?\n");
1837 return -1;
1838 }
1839 }
1840 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1841 pDevModeInput, NULL, fMode);
1842
1843 if(!pDeviceName)
1844 HeapFree(GetProcessHeap(),0,lpName);
1845 return ret;
1846 }
1847
1848
1849 /*****************************************************************************
1850 * DocumentPropertiesW (WINSPOOL.@)
1851 *
1852 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1853 */
1854 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1855 LPWSTR pDeviceName,
1856 LPDEVMODEW pDevModeOutput,
1857 LPDEVMODEW pDevModeInput, DWORD fMode)
1858 {
1859
1860 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1861 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1862 LPDEVMODEA pDevModeOutputA = NULL;
1863 LONG ret;
1864
1865 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1866 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1867 fMode);
1868 if(pDevModeOutput) {
1869 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1870 if(ret < 0) return ret;
1871 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1872 }
1873 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1874 pDevModeInputA, fMode);
1875 if(pDevModeOutput) {
1876 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1877 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1878 }
1879 if(fMode == 0 && ret > 0)
1880 ret += (CCHDEVICENAME + CCHFORMNAME);
1881 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1882 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1883 return ret;
1884 }
1885
1886 /*****************************************************************************
1887 * IsValidDevmodeA [WINSPOOL.@]
1888 *
1889 * Validate a DEVMODE structure and fix errors if possible.
1890 *
1891 */
1892 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
1893 {
1894 FIXME("(%p,%ld): stub\n", pDevMode, size);
1895
1896 if(!pDevMode)
1897 return FALSE;
1898
1899 return TRUE;
1900 }
1901
1902 /*****************************************************************************
1903 * IsValidDevmodeW [WINSPOOL.@]
1904 *
1905 * Validate a DEVMODE structure and fix errors if possible.
1906 *
1907 */
1908 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
1909 {
1910 FIXME("(%p,%ld): stub\n", pDevMode, size);
1911
1912 if(!pDevMode)
1913 return FALSE;
1914
1915 return TRUE;
1916 }
1917
1918 /******************************************************************
1919 * OpenPrinterA [WINSPOOL.@]
1920 *
1921 * See OpenPrinterW.
1922 *
1923 */
1924 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1925 LPPRINTER_DEFAULTSA pDefault)
1926 {
1927 UNICODE_STRING lpPrinterNameW;
1928 UNICODE_STRING usBuffer;
1929 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1930 PWSTR pwstrPrinterNameW;
1931 BOOL ret;
1932
1933 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1934
1935 if(pDefault) {
1936 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1937 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1938 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1939 pDefaultW = &DefaultW;
1940 }
1941 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1942 if(pDefault) {
1943 RtlFreeUnicodeString(&usBuffer);
1944 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1945 }
1946 RtlFreeUnicodeString(&lpPrinterNameW);
1947 return ret;
1948 }
1949
1950 /******************************************************************
1951 * OpenPrinterW [WINSPOOL.@]
1952 *
1953 * Open a Printer / Printserver or a Printer-Object
1954 *
1955 * PARAMS
1956 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1957 * phPrinter [O] The resulting Handle is stored here
1958 * pDefault [I] PTR to Default Printer Settings or NULL
1959 *
1960 * RETURNS
1961 * Success: TRUE
1962 * Failure: FALSE
1963 *
1964 * NOTES
1965 * lpPrinterName is one of:
1966 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1967 *| Printer: "PrinterName"
1968 *| Printer-Object: "PrinterName,Job xxx"
1969 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1970 *| XcvPort: "Servername,XcvPort PortName"
1971 *
1972 * BUGS
1973 *| Printer-Object not supported
1974 *| pDefaults is ignored
1975 *
1976 */
1977 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1978 {
1979
1980 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1981
1982 if(!phPrinter) {
1983 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1984 SetLastError(ERROR_INVALID_PARAMETER);
1985 return FALSE;
1986 }
1987
1988 /* Get the unique handle of the printer or Printserver */
1989 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1990 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1991 return (*phPrinter != 0);
1992 }
1993
1994 /******************************************************************
1995 * AddMonitorA [WINSPOOL.@]
1996 *
1997 * See AddMonitorW.
1998 *
1999 */
2000 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2001 {
2002 LPWSTR nameW = NULL;
2003 INT len;
2004 BOOL res;
2005 LPMONITOR_INFO_2A mi2a;
2006 MONITOR_INFO_2W mi2w;
2007
2008 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2009 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2010 debugstr_a(mi2a ? mi2a->pName : NULL),
2011 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2012 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2013
2014 if (Level != 2) {
2015 SetLastError(ERROR_INVALID_LEVEL);
2016 return FALSE;
2017 }
2018
2019 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2020 if (mi2a == NULL) {
2021 return FALSE;
2022 }
2023
2024 if (pName) {
2025 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2026 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2027 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2028 }
2029
2030 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2031 if (mi2a->pName) {
2032 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2033 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2034 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2035 }
2036 if (mi2a->pEnvironment) {
2037 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2038 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2039 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2040 }
2041 if (mi2a->pDLLName) {
2042 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2043 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2044 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2045 }
2046
2047 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2048
2049 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2050 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2051 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2052
2053 HeapFree(GetProcessHeap(), 0, nameW);
2054 return (res);
2055 }
2056
2057 /******************************************************************************
2058 * AddMonitorW [WINSPOOL.@]
2059 *
2060 * Install a Printmonitor
2061 *
2062 * PARAMS
2063 * pName [I] Servername or NULL (local Computer)
2064 * Level [I] Structure-Level (Must be 2)
2065 * pMonitors [I] PTR to MONITOR_INFO_2
2066 *
2067 * RETURNS
2068 * Success: TRUE
2069 * Failure: FALSE
2070 *
2071 * NOTES
2072 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2073 *
2074 */
2075 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2076 {
2077 LPMONITOR_INFO_2W mi2w;
2078
2079 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2080 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2081 debugstr_w(mi2w ? mi2w->pName : NULL),
2082 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2083 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2084
2085 if ((backend == NULL) && !load_backend()) return FALSE;
2086
2087 if (Level != 2) {
2088 SetLastError(ERROR_INVALID_LEVEL);
2089 return FALSE;
2090 }
2091
2092 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2093 if (mi2w == NULL) {
2094 return FALSE;
2095 }
2096
2097 return backend->fpAddMonitor(pName, Level, pMonitors);
2098 }
2099
2100 /******************************************************************
2101 * DeletePrinterDriverA [WINSPOOL.@]
2102 *
2103 */
2104 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2105 {
2106 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2107 }
2108
2109 /******************************************************************
2110 * DeletePrinterDriverW [WINSPOOL.@]
2111 *
2112 */
2113 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2114 {
2115 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2116 }
2117
2118 /******************************************************************
2119 * DeleteMonitorA [WINSPOOL.@]
2120 *
2121 * See DeleteMonitorW.
2122 *
2123 */
2124 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2125 {
2126 LPWSTR nameW = NULL;
2127 LPWSTR EnvironmentW = NULL;
2128 LPWSTR MonitorNameW = NULL;
2129 BOOL res;
2130 INT len;
2131
2132 if (pName) {
2133 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2134 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2135 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2136 }
2137
2138 if (pEnvironment) {
2139 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2140 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2141 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2142 }
2143 if (pMonitorName) {
2144 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2145 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2146 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2147 }
2148
2149 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2150
2151 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2152 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2153 HeapFree(GetProcessHeap(), 0, nameW);
2154 return (res);
2155 }
2156
2157 /******************************************************************
2158 * DeleteMonitorW [WINSPOOL.@]
2159 *
2160 * Delete a specific Printmonitor from a Printing-Environment
2161 *
2162 * PARAMS
2163 * pName [I] Servername or NULL (local Computer)
2164 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2165 * pMonitorName [I] Name of the Monitor, that should be deleted
2166 *
2167 * RETURNS
2168 * Success: TRUE
2169 * Failure: FALSE
2170 *
2171 * NOTES
2172 * pEnvironment is ignored in Windows for the local Computer.
2173 *
2174 */
2175 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2176 {
2177
2178 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2179 debugstr_w(pMonitorName));
2180
2181 if ((backend == NULL) && !load_backend()) return FALSE;
2182
2183 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2184 }
2185
2186
2187 /******************************************************************
2188 * DeletePortA [WINSPOOL.@]
2189 *
2190 * See DeletePortW.
2191 *
2192 */
2193 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2194 {
2195 LPWSTR nameW = NULL;
2196 LPWSTR portW = NULL;
2197 INT len;
2198 DWORD res;
2199
2200 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2201
2202 /* convert servername to unicode */
2203 if (pName) {
2204 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2205 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2206 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2207 }
2208
2209 /* convert portname to unicode */
2210 if (pPortName) {
2211 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2212 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2213 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2214 }
2215
2216 res = DeletePortW(nameW, hWnd, portW);
2217 HeapFree(GetProcessHeap(), 0, nameW);
2218 HeapFree(GetProcessHeap(), 0, portW);
2219 return res;
2220 }
2221
2222 /******************************************************************
2223 * DeletePortW [WINSPOOL.@]
2224 *
2225 * Delete a specific Port
2226 *
2227 * PARAMS
2228 * pName [I] Servername or NULL (local Computer)
2229 * hWnd [I] Handle to parent Window for the Dialog-Box
2230 * pPortName [I] Name of the Port, that should be deleted
2231 *
2232 * RETURNS
2233 * Success: TRUE
2234 * Failure: FALSE
2235 *
2236 */
2237 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2238 {
2239 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2240
2241 if ((backend == NULL) && !load_backend()) return FALSE;
2242
2243 if (!pPortName) {
2244 SetLastError(RPC_X_NULL_REF_POINTER);
2245 return FALSE;
2246 }
2247
2248 return backend->fpDeletePort(pName, hWnd, pPortName);
2249 }
2250
2251 /******************************************************************************
2252 * WritePrinter [WINSPOOL.@]
2253 */
2254 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2255 {
2256 opened_printer_t *printer;
2257 BOOL ret = FALSE;
2258
2259 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2260
2261 EnterCriticalSection(&printer_handles_cs);
2262 printer = get_opened_printer(hPrinter);
2263 if(!printer)
2264 {
2265 SetLastError(ERROR_INVALID_HANDLE);
2266 goto end;
2267 }
2268
2269 if(!printer->doc)
2270 {
2271 SetLastError(ERROR_SPL_NO_STARTDOC);
2272 goto end;
2273 }
2274
2275 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2276 end:
2277 LeaveCriticalSection(&printer_handles_cs);
2278 return ret;
2279 }
2280
2281 /*****************************************************************************
2282 * AddFormA [WINSPOOL.@]
2283 */
2284 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2285 {
2286 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2287 return 1;
2288 }
2289
2290 /*****************************************************************************
2291 * AddFormW [WINSPOOL.@]
2292 */
2293 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2294 {
2295 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2296 return 1;
2297 }
2298
2299 /*****************************************************************************
2300 * AddJobA [WINSPOOL.@]
2301 */
2302 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2303 {
2304 BOOL ret;
2305 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2306 DWORD needed;
2307
2308 if(Level != 1) {
2309 SetLastError(ERROR_INVALID_LEVEL);
2310 return FALSE;
2311 }
2312
2313 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2314
2315 if(ret) {
2316 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2317 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2318 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2319 if(*pcbNeeded > cbBuf) {
2320 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2321 ret = FALSE;
2322 } else {
2323 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2324 addjobA->JobId = addjobW->JobId;
2325 addjobA->Path = (char *)(addjobA + 1);
2326 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2327 }
2328 }
2329 return ret;
2330 }
2331
2332 /*****************************************************************************
2333 * AddJobW [WINSPOOL.@]
2334 */
2335 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2336 {
2337 opened_printer_t *printer;
2338 job_t *job;
2339 BOOL ret = FALSE;
2340 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2341 static const WCHAR fmtW[] = {'%','s','%','','5','d','.','S','P','L',0};
2342 WCHAR path[MAX_PATH], filename[MAX_PATH];
2343 DWORD len;
2344 ADDJOB_INFO_1W *addjob;
2345
2346 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2347
2348 EnterCriticalSection(&printer_handles_cs);
2349
2350 printer = get_opened_printer(hPrinter);
2351
2352 if(!printer) {
2353 SetLastError(ERROR_INVALID_HANDLE);
2354 goto end;
2355 }
2356
2357 if(Level != 1) {
2358 SetLastError(ERROR_INVALID_LEVEL);
2359 goto end;
2360 }
2361
2362 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2363 if(!job)
2364 goto end;
2365
2366 job->job_id = InterlockedIncrement(&next_job_id);
2367
2368 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2369 if(path[len - 1] != '\\')
2370 path[len++] = '\\';
2371 memcpy(path + len, spool_path, sizeof(spool_path));
2372 sprintfW(filename, fmtW, path, job->job_id);
2373
2374 len = strlenW(filename);
2375 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2376 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2377 job->portname = NULL;
2378 job->document_title = strdupW(default_doc_title);
2379 job->printer_name = strdupW(printer->name);
2380 job->devmode = dup_devmode( printer->devmode );
2381 list_add_tail(&printer->queue->jobs, &job->entry);
2382
2383 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2384 if(*pcbNeeded <= cbBuf) {
2385 addjob = (ADDJOB_INFO_1W*)pData;
2386 addjob->JobId = job->job_id;
2387 addjob->Path = (WCHAR *)(addjob + 1);
2388 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2389 ret = TRUE;
2390 } else
2391 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2392
2393 end:
2394 LeaveCriticalSection(&printer_handles_cs);
2395 return ret;
2396 }
2397
2398 /*****************************************************************************
2399 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2400 *
2401 * Return the PATH for the Print-Processors
2402 *
2403 * See GetPrintProcessorDirectoryW.
2404 *
2405 *
2406 */
2407 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2408 DWORD level, LPBYTE Info,
2409 DWORD cbBuf, LPDWORD pcbNeeded)
2410 {
2411 LPWSTR serverW = NULL;
2412 LPWSTR envW = NULL;
2413 BOOL ret;
2414 INT len;
2415
2416 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2417 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2418
2419
2420 if (server) {
2421 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2422 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2423 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2424 }
2425
2426 if (env) {
2427 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2428 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2429 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2430 }
2431
2432 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2433 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2434 */
2435 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2436 cbBuf, pcbNeeded);
2437
2438 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2439 cbBuf, NULL, NULL) > 0;
2440
2441
2442 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2443 HeapFree(GetProcessHeap(), 0, envW);
2444 HeapFree(GetProcessHeap(), 0, serverW);
2445 return ret;
2446 }
2447
2448 /*****************************************************************************
2449 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2450 *
2451 * Return the PATH for the Print-Processors
2452 *
2453 * PARAMS
2454 * server [I] Servername (NT only) or NULL (local Computer)
2455 * env [I] Printing-Environment (see below) or NULL (Default)
2456 * level [I] Structure-Level (must be 1)
2457 * Info [O] PTR to Buffer that receives the Result
2458 * cbBuf [I] Size of Buffer at "Info"
2459 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2460 * required for the Buffer at "Info"
2461 *
2462 * RETURNS
2463 * Success: TRUE and in pcbNeeded the Bytes used in Info
2464 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2465 * if cbBuf is too small
2466 *
2467 * Native Values returned in Info on Success:
2468 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2469 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2470 *| win9x(Windows 4.0): "%winsysdir%"
2471 *
2472 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2473 *
2474 * BUGS
2475 * Only NULL or "" is supported for server
2476 *
2477 */
2478 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2479 DWORD level, LPBYTE Info,
2480 DWORD cbBuf, LPDWORD pcbNeeded)
2481 {
2482
2483 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2484 Info, cbBuf, pcbNeeded);
2485
2486 if ((backend == NULL) && !load_backend()) return FALSE;
2487
2488 if (level != 1) {
2489 /* (Level != 1) is ignored in win9x */
2490 SetLastError(ERROR_INVALID_LEVEL);
2491 return FALSE;
2492 }
2493
2494 if (pcbNeeded == NULL) {
2495 /* (pcbNeeded == NULL) is ignored in win9x */
2496 SetLastError(RPC_X_NULL_REF_POINTER);
2497 return FALSE;
2498 }
2499
2500 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2501 }
2502
2503 /*****************************************************************************
2504 * WINSPOOL_OpenDriverReg [internal]
2505 *
2506 * opens the registry for the printer drivers depending on the given input
2507 * variable pEnvironment
2508 *
2509 * RETURNS:
2510 * the opened hkey on success
2511 * NULL on error
2512 */
2513 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
2514 {
2515 HKEY retval = NULL;
2516 LPWSTR buffer;
2517 const printenv_t * env;
2518
2519 TRACE("(%s)\n", debugstr_w(pEnvironment));
2520
2521 env = validate_envW(pEnvironment);
2522 if (!env) return NULL;
2523
2524 buffer = HeapAlloc( GetProcessHeap(), 0,
2525 (strlenW(DriversW) + strlenW(env->envname) +
2526 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2527 if(buffer) {
2528 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2529 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2530 HeapFree(GetProcessHeap(), 0, buffer);
2531 }
2532 return retval;
2533 }
2534
2535 /*****************************************************************************
2536 * set_devices_and_printerports [internal]
2537 *
2538 * set the [Devices] and [PrinterPorts] entries for a printer.
2539 *
2540 */
2541 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
2542 {
2543 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
2544 WCHAR *devline;
2545 HKEY hkey;
2546
2547 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
2548
2549 /* FIXME: the driver must change to "winspool" */
2550 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
2551 if (devline) {
2552 lstrcpyW(devline, driver_nt);
2553 lstrcatW(devline, commaW);
2554 lstrcatW(devline, pi->pPortName);
2555
2556 TRACE("using %s\n", debugstr_w(devline));
2557 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
2558 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
2559 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2560 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2561 RegCloseKey(hkey);
2562 }
2563
2564 lstrcatW(devline, timeout_15_45);
2565 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
2566 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
2567 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2568 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2569 RegCloseKey(hkey);
2570 }
2571 HeapFree(GetProcessHeap(), 0, devline);
2572 }
2573 }
2574
2575 /*****************************************************************************
2576 * AddPrinterW [WINSPOOL.@]
2577 */
2578 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2579 {
2580 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2581 LPDEVMODEW dm;
2582 HANDLE retval;
2583 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2584 LONG size;
2585 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2586 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2587 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2588 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2589 statusW[] = {'S','t','a','t','u','s',0},
2590 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2591
2592 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2593
2594 if(pName != NULL) {
2595 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2596 SetLastError(ERROR_INVALID_PARAMETER);
2597 return 0;
2598 }
2599 if(Level != 2) {
2600 ERR("Level = %d, unsupported!\n", Level);
2601 SetLastError(ERROR_INVALID_LEVEL);
2602 return 0;
2603 }
2604 if(!pPrinter) {
2605 SetLastError(ERROR_INVALID_PARAMETER);
2606 return 0;
2607 }
2608 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2609 ERROR_SUCCESS) {
2610 ERR("Can't create Printers key\n");
2611 return 0;
2612 }
2613 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2614 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2615 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2616 RegCloseKey(hkeyPrinter);
2617 RegCloseKey(hkeyPrinters);
2618 return 0;
2619 }
2620 RegCloseKey(hkeyPrinter);
2621 }
2622 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
2623 if(!hkeyDrivers) {
2624 ERR("Can't create Drivers key\n");
2625 RegCloseKey(hkeyPrinters);
2626 return 0;
2627 }
2628 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2629 ERROR_SUCCESS) {
2630 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2631 RegCloseKey(hkeyPrinters);
2632 RegCloseKey(hkeyDrivers);
2633 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2634 return 0;
2635 }
2636 RegCloseKey(hkeyDriver);
2637 RegCloseKey(hkeyDrivers);
2638
2639 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2640 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2641 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2642 RegCloseKey(hkeyPrinters);
2643 return 0;
2644 }
2645
2646 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2647 ERROR_SUCCESS) {
2648 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2649 SetLastError(ERROR_INVALID_PRINTER_NAME);
2650 RegCloseKey(hkeyPrinters);
2651 return 0;
2652 }
2653
2654 set_devices_and_printerports(pi);
2655 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2656 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2657 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2658
2659 /* See if we can load the driver. We may need the devmode structure anyway
2660 *
2661 * FIXME:
2662 * Note that DocumentPropertiesW will briefly try to open the printer we
2663 * just create to find a DEVMODE struct (it will use the WINEPS default
2664 * one in case it is not there, so we are ok).
2665 */
2666 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2667
2668 if(size < 0) {
2669 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2670 size = sizeof(DEVMODEW);
2671 }
2672 if(pi->pDevMode)
2673 dm = pi->pDevMode;
2674 else
2675 {
2676 dm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
2677 dm->dmSize = size;
2678 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
2679 {
2680 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2681 HeapFree( GetProcessHeap(), 0, dm );
2682 dm = NULL;
2683 }
2684 else
2685 {
2686 /* set devmode to printer name */
2687 lstrcpynW( dm->dmDeviceName, pi->pPrinterName, CCHDEVICENAME );
2688 }
2689 }
2690
2691 set_reg_devmode( hkeyPrinter, default_devmodeW, dm );
2692 if (!pi->pDevMode) HeapFree( GetProcessHeap(), 0, dm );
2693
2694 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2695 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2696 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2697 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2698
2699 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2700 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2701 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2702 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2703 (LPBYTE)&pi->Priority, sizeof(DWORD));
2704 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2705 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2706 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2707 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2708 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2709 (LPBYTE)&pi->Status, sizeof(DWORD));
2710 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2711 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2712
2713 RegCloseKey(hkeyPrinter);
2714 RegCloseKey(hkeyPrinters);
2715 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2716 ERR("OpenPrinter failing\n");
2717 return 0;
2718 }
2719 return retval;
2720 }
2721
2722 /*****************************************************************************
2723 * AddPrinterA [WINSPOOL.@]
2724 */
2725 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2726 {
2727 UNICODE_STRING pNameW;
2728 PWSTR pwstrNameW;
2729 PRINTER_INFO_2W *piW;
2730 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2731 HANDLE ret;
2732
2733 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
2734 if(Level != 2) {
2735 ERR("Level = %d, unsupported!\n", Level);
2736 SetLastError(ERROR_INVALID_LEVEL);
2737 return 0;
2738 }
2739 pwstrNameW = asciitounicode(&pNameW,pName);
2740 piW = printer_info_AtoW( piA, Level );
2741
2742 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2743
2744 free_printer_info( piW, Level );
2745 RtlFreeUnicodeString(&pNameW);
2746 return ret;
2747 }
2748
2749
2750 /*****************************************************************************
2751 * ClosePrinter [WINSPOOL.@]
2752 */
2753 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2754 {
2755 UINT_PTR i = (UINT_PTR)hPrinter;
2756 opened_printer_t *printer = NULL;
2757 BOOL ret = FALSE;
2758
2759 TRACE("(%p)\n", hPrinter);
2760
2761 EnterCriticalSection(&printer_handles_cs);
2762
2763 if ((i > 0) && (i <= nb_printer_handles))
2764 printer = printer_handles[i - 1];
2765
2766
2767 if(printer)
2768 {
2769 struct list *cursor, *cursor2;
2770
2771 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2772
2773 if (printer->backend_printer) {
2774 backend->fpClosePrinter(printer->backend_printer);
2775 }
2776
2777 if(printer->doc)
2778 EndDocPrinter(hPrinter);
2779
2780 if(InterlockedDecrement(&printer->queue->ref) == 0)
2781 {
2782 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2783 {
2784 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2785 ScheduleJob(hPrinter, job->job_id);
2786 }
2787 HeapFree(GetProcessHeap(), 0, printer->queue);
2788 }
2789
2790 free_printer_entry( printer );
2791 printer_handles[i - 1] = NULL;
2792 ret = TRUE;
2793 }
2794 LeaveCriticalSection(&printer_handles_cs);
2795 return ret;
2796 }
2797
2798 /*****************************************************************************
2799 * DeleteFormA [WINSPOOL.@]
2800 */
2801 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2802 {
2803 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2804 return 1;
2805 }
2806
2807 /*****************************************************************************
2808 * DeleteFormW [WINSPOOL.@]
2809 */
2810 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2811 {
2812 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2813 return 1;
2814 }
2815
2816 /*****************************************************************************
2817 * DeletePrinter [WINSPOOL.@]
2818 */
2819 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2820 {
2821 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2822 HKEY hkeyPrinters, hkey;
2823 WCHAR def[MAX_PATH];
2824 DWORD size = sizeof( def ) / sizeof( def[0] );
2825
2826 if(!lpNameW) {
2827 SetLastError(ERROR_INVALID_HANDLE);
2828 return FALSE;
2829 }
2830 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2831 RegDeleteTreeW(hkeyPrinters, lpNameW);
2832 RegCloseKey(hkeyPrinters);
2833 }
2834 WriteProfileStringW(devicesW, lpNameW, NULL);
2835 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2836
2837 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2838 RegDeleteValueW(hkey, lpNameW);
2839 RegCloseKey(hkey);
2840 }
2841
2842 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2843 RegDeleteValueW(hkey, lpNameW);
2844 RegCloseKey(hkey);
2845 }
2846
2847 if (GetDefaultPrinterW( def, &size ) && !strcmpW( def, lpNameW ))
2848 {
2849 WriteProfileStringW( windowsW, deviceW, NULL );
2850 if (!RegCreateKeyW( HKEY_CURRENT_USER, user_default_reg_key, &hkey ))
2851 {
2852 RegDeleteValueW( hkey, deviceW );
2853 RegCloseKey( hkey );
2854 }
2855 SetDefaultPrinterW( NULL );
2856 }
2857
2858 return TRUE;
2859 }
2860
2861 /*****************************************************************************
2862 * SetPrinterA [WINSPOOL.@]
2863 */
2864 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
2865 {
2866 BYTE *dataW = data;
2867 BOOL ret;
2868
2869 if (level != 0)
2870 {
2871 dataW = printer_info_AtoW( data, level );
2872 if (!dataW) return FALSE;
2873 }
2874
2875 ret = SetPrinterW( printer, level, dataW, command );
2876
2877 if (dataW != data) free_printer_info( dataW, level );
2878
2879 return ret;
2880 }
2881
2882 static void set_printer_2( HKEY key, const PRINTER_INFO_2W *pi )
2883 {
2884 set_reg_szW( key, NameW, pi->pPrinterName );
2885 set_reg_szW( key, Share_NameW, pi->pShareName );
2886 set_reg_szW( key, PortW, pi->pPortName );
2887 set_reg_szW( key, Printer_DriverW, pi->pDriverName );
2888 set_reg_szW( key, DescriptionW, pi->pComment );
2889 set_reg_szW( key, LocationW, pi->pLocation );
2890
2891 if (pi->pDevMode)
2892 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
2893
2894 set_reg_szW( key, Separator_FileW, pi->pSepFile );
2895 set_reg_szW( key, Print_ProcessorW, pi->pPrintProcessor );
2896 set_reg_szW( key, DatatypeW, pi->pDatatype );
2897 set_reg_szW( key, ParametersW, pi->pParameters );
2898
2899 set_reg_DWORD( key, "Attributes", pi->Attributes );
2900 set_reg_DWORD( key, "Priority", pi->Priority );
2901 set_reg_DWORD( key, "Default Priority", pi->DefaultPriority );
2902 set_reg_DWORD( key, "StartTime", pi->StartTime );
2903 set_reg_DWORD( key, "UntilTime", pi->UntilTime );
2904 }
2905
2906 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
2907 {
2908 if (!pi->pDevMode) return FALSE;
2909
2910 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
2911 return TRUE;
2912 }
2913
2914 /******************************************************************************
2915 * SetPrinterW [WINSPOOL.@]
2916 */
2917 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
2918 {
2919 HKEY key;
2920 BOOL ret = FALSE;
2921
2922 TRACE( "(%p, %d, %p, %d)\n", printer, level, data, command );
2923
2924 if (command != 0) FIXME( "Ignoring command %d\n", command );
2925
2926 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
2927 return FALSE;
2928
2929 switch (level)
2930 {
2931 case 2:
2932 {
2933 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)data;
2934 set_printer_2( key, pi2 );
2935 ret = TRUE;
2936 break;
2937 }
2938
2939 case 9:
2940 {
2941 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
2942 ret = set_printer_9( key, pi );
2943 break;
2944 }
2945
2946 default:
2947 FIXME( "Unimplemented level %d\n", level );
2948 SetLastError( ERROR_INVALID_LEVEL );
2949 }
2950
2951 RegCloseKey( key );
2952 return ret;
2953 }
2954
2955 /*****************************************************************************
2956 * SetJobA [WINSPOOL.@]
2957 */
2958 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2959 LPBYTE pJob, DWORD Command)
2960 {
2961 BOOL ret;
2962 LPBYTE JobW;
2963 UNICODE_STRING usBuffer;
2964
2965 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2966
2967 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2968 are all ignored by SetJob, so we don't bother copying them */
2969 switch(Level)
2970 {
2971 case 0:
2972 JobW = NULL;
2973 break;
2974 case 1:
2975 {
2976 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2977 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2978
2979 JobW = (LPBYTE)info1W;
2980 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2981 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2982 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2983 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2984 info1W->Status = info1A->Status;
2985 info1W->Priority = info1A->Priority;
2986 info1W->Position = info1A->Position;
2987 info1W->PagesPrinted = info1A->PagesPrinted;
2988 break;
2989 }
2990 case 2:
2991 {
2992 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2993 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2994
2995 JobW = (LPBYTE)info2W;
2996 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2997 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2998 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2999 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3000 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3001 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3002 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3003 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3004 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3005 info2W->Status = info2A->Status;
3006 info2W->Priority = info2A->Priority;
3007 info2W->Position = info2A->Position;
3008 info2W->StartTime = info2A->StartTime;
3009 info2W->UntilTime = info2A->UntilTime;
3010 info2W->PagesPrinted = info2A->PagesPrinted;
3011 break;
3012 }
3013 case 3:
3014 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3015 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3016 break;
3017 default:
3018 SetLastError(ERROR_INVALID_LEVEL);
3019 return FALSE;
3020 }
3021
3022 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3023
3024 switch(Level)
3025 {
3026 case 1:
3027 {
3028 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3029 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3030 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3031 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3032 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3033 break;
3034 }
3035 case 2:
3036 {
3037 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3038 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3039 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3040 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3041 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3042 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3043 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3044 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3045 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3046 break;
3047 }
3048 }
3049 HeapFree(GetProcessHeap(), 0, JobW);
3050
3051 return ret;
3052 }
3053
3054 /*****************************************************************************
3055 * SetJobW [WINSPOOL.@]
3056 */
3057 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3058 LPBYTE pJob, DWORD Command)
3059 {
3060 BOOL ret = FALSE;
3061 job_t *job;
3062
3063 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3064 FIXME("Ignoring everything other than document title\n");
3065
3066 EnterCriticalSection(&printer_handles_cs);
3067 job = get_job(hPrinter, JobId);
3068 if(!job)
3069 goto end;
3070
3071 switch(Level)
3072 {
3073 case 0:
3074 break;
3075 case 1:
3076 {
3077 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3078 HeapFree(GetProcessHeap(), 0, job->document_title);
3079 job->document_title = strdupW(info1->pDocument);
3080 break;
3081 }
3082 case 2:
3083 {
3084 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3085 HeapFree(GetProcessHeap(), 0, job->document_title);
3086 job->document_title = strdupW(info2->pDocument);
3087 HeapFree(GetProcessHeap(), 0, job->devmode);
3088 job->devmode = dup_devmode( info2->pDevMode );
3089 break;
3090 }
3091 case 3:
3092 break;
3093 default:
3094 SetLastError(ERROR_INVALID_LEVEL);
3095 goto end;
3096 }
3097 ret = TRUE;
3098 end:
3099 LeaveCriticalSection(&printer_handles_cs);
3100 return ret;
3101 }
3102
3103 /*****************************************************************************
3104 * EndDocPrinter [WINSPOOL.@]
3105 */
3106 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3107 {
3108 opened_printer_t *printer;
3109 BOOL ret = FALSE;
3110 TRACE("(%p)\n", hPrinter);
3111
3112 EnterCriticalSection(&printer_handles_cs);
3113
3114 printer = get_opened_printer(hPrinter);
3115 if(!printer)
3116 {
3117 SetLastError(ERROR_INVALID_HANDLE);
3118 goto end;
3119 }
3120
3121 if(!printer->doc)
3122 {
3123 SetLastError(ERROR_SPL_NO_STARTDOC);
3124 goto end;
3125 }
3126
3127 CloseHandle(printer->doc->hf);
3128 ScheduleJob(hPrinter, printer->doc->job_id);
3129 HeapFree(GetProcessHeap(), 0, printer->doc);
3130 printer->doc = NULL;
3131 ret = TRUE;
3132 end:
3133 LeaveCriticalSection(&printer_handles_cs);
3134 return ret;
3135 }
3136
3137 /*****************************************************************************
3138 * EndPagePrinter [WINSPOOL.@]
3139 */
3140 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3141 {
3142 FIXME("(%p): stub\n", hPrinter);
3143 return TRUE;
3144 }
3145
3146 /*****************************************************************************
3147 * StartDocPrinterA [WINSPOOL.@]
3148 */
3149 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3150 {
3151 UNICODE_STRING usBuffer;
3152 DOC_INFO_2W doc2W;
3153 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3154 DWORD ret;
3155
3156 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3157 or one (DOC_INFO_3) extra DWORDs */
3158
3159 switch(Level) {
3160 case 2:
3161 doc2W.JobId = doc2->JobId;
3162 /* fall through */
3163 case 3:
3164 doc2W.dwMode = doc2->dwMode;
3165 /* fall through */
3166 case 1:
3167 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3168 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3169 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3170 break;
3171
3172 default:
3173 SetLastError(ERROR_INVALID_LEVEL);
3174 return FALSE;
3175 }
3176
3177 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3178
3179 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3180 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3181 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3182
3183 return ret;
3184 }
3185
3186 /*****************************************************************************
3187 * StartDocPrinterW [WINSPOOL.@]
3188 */
3189 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3190 {
3191 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3192 opened_printer_t *printer;
3193 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3194 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3195 JOB_INFO_1W job_info;
3196 DWORD needed, ret = 0;
3197 HANDLE hf;
3198 WCHAR *filename;
3199 job_t *job;
3200
3201 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3202 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3203 debugstr_w(doc->pDatatype));
3204
3205 if(Level < 1 || Level > 3)
3206 {
3207 SetLastError(ERROR_INVALID_LEVEL);
3208 return 0;
3209 }
3210
3211 EnterCriticalSection(&printer_handles_cs);
3212 printer = get_opened_printer(hPrinter);
3213 if(!printer)
3214 {
3215 SetLastError(ERROR_INVALID_HANDLE);
3216 goto end;
3217 }
3218
3219 if(printer->doc)
3220 {
3221 SetLastError(ERROR_INVALID_PRINTER_STATE);
3222 goto end;
3223 }
3224
3225 /* Even if we're printing to a file we still add a print job, we'll
3226 just ignore the spool file name */
3227
3228 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3229 {
3230 ERR("AddJob failed gle %u\n", GetLastError());
3231 goto end;
3232 }
3233
3234 /* use pOutputFile only, when it is a real filename */
3235 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3236 filename = doc->pOutputFile;
3237 else
3238 filename = addjob->Path;
3239
3240 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3241 if(hf == INVALID_HANDLE_VALUE)
3242 goto end;
3243
3244 memset(&job_info, 0, sizeof(job_info));
3245 job_info.pDocument = doc->pDocName;
3246 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3247
3248 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3249 printer->doc->hf = hf;
3250 ret = printer->doc->job_id = addjob->JobId;
3251 job = get_job(hPrinter, ret);
3252 job->portname = strdupW(doc->pOutputFile);
3253
3254 end:
3255 LeaveCriticalSection(&printer_handles_cs);
3256
3257 return ret;
3258 }
3259
3260 /*****************************************************************************
3261 * StartPagePrinter [WINSPOOL.@]
3262 */
3263 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3264 {
3265 FIXME("(%p): stub\n", hPrinter);
3266 return TRUE;
3267 }
3268
3269 /*****************************************************************************
3270 * GetFormA [WINSPOOL.@]
3271 */
3272 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3273 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3274 {
3275 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3276 Level,pForm,cbBuf,pcbNeeded);
3277 return FALSE;
3278 }
3279
3280 /*****************************************************************************
3281 * GetFormW [WINSPOOL.@]
3282 */
3283 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3284 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3285 {
3286 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3287 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3288 return FALSE;
3289 }
3290
3291 /*****************************************************************************
3292 * SetFormA [WINSPOOL.@]
3293 */
3294 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3295 LPBYTE pForm)
3296 {
3297 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3298 return FALSE;
3299 }
3300
3301 /*****************************************************************************
3302 * SetFormW [WINSPOOL.@]
3303 */
3304 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3305 LPBYTE pForm)
3306 {
3307 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3308 return FALSE;
3309 }
3310
3311 /*****************************************************************************
3312 * ReadPrinter [WINSPOOL.@]
3313 */
3314 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3315 LPDWORD pNoBytesRead)
3316 {
3317 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3318 return FALSE;
3319 }
3320
3321 /*****************************************************************************
3322 * ResetPrinterA [WINSPOOL.@]
3323 */
3324 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3325 {
3326 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3327 return FALSE;
3328 }
3329
3330 /*****************************************************************************
3331 * ResetPrinterW [WINSPOOL.@]
3332 */
3333 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3334 {
3335 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3336 return FALSE;
3337 }
3338
3339 /*****************************************************************************
3340 * WINSPOOL_GetDWORDFromReg
3341 *
3342 * Return DWORD associated with ValueName from hkey.
3343 */
3344 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3345 {
3346 DWORD sz = sizeof(DWORD), type, value = 0;
3347 LONG ret;
3348
3349 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3350
3351 if(ret != ERROR_SUCCESS) {
3352 WARN("Got ret = %d on name %s\n", ret, ValueName);
3353 return 0;
3354 }
3355 if(type != REG_DWORD) {
3356 ERR("Got type %d\n", type);
3357 return 0;
3358 }
3359 return value;
3360 }
3361
3362
3363 /*****************************************************************************
3364 * get_filename_from_reg [internal]
3365 *
3366 * Get ValueName from hkey storing result in out
3367 * when the Value in the registry has only a filename, use driverdir as prefix
3368 * outlen is space left in out
3369 * String is stored either as unicode or ascii
3370 *
3371 */
3372
3373 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3374 LPBYTE out, DWORD outlen, LPDWORD needed)
3375 {
3376 WCHAR filename[MAX_PATH];
3377 DWORD size;
3378 DWORD type;
3379 LONG ret;
3380 LPWSTR buffer = filename;
3381 LPWSTR ptr;
3382
3383 *needed = 0;
3384 size = sizeof(filename);
3385 buffer[0] = '\0';
3386 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3387 if (ret == ERROR_MORE_DATA) {
3388 TRACE("need dynamic buffer: %u\n", size);
3389 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3390 if (!buffer) {
3391 /* No Memory is bad */
3392 return FALSE;
3393 }
3394 buffer[0] = '\0';
3395 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3396 }
3397
3398 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3399 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3400 return FALSE;
3401 }
3402
3403 ptr = buffer;
3404 while (ptr) {
3405 /* do we have a full path ? */
3406 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3407 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3408
3409 if (!ret) {
3410 /* we must build the full Path */
3411 *needed += dirlen;
3412 if ((out) && (outlen > dirlen)) {
3413 lstrcpyW((LPWSTR)out, driverdir);
3414 out += dirlen;
3415 outlen -= dirlen;
3416 }
3417 else
3418 out = NULL;
3419 }
3420
3421 /* write the filename */
3422 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3423 if ((out) && (outlen >= size)) {
3424 lstrcpyW((LPWSTR)out, ptr);
3425 out += size;
3426 outlen -= size;
3427 }
3428 else
3429 out = NULL;
3430 *needed += size;
3431 ptr += lstrlenW(ptr)+1;
3432 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3433 }
3434
3435 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3436
3437 /* write the multisz-termination */
3438 if (type == REG_MULTI_SZ) {
3439 size = sizeof(WCHAR);
3440
3441 *needed += size;
3442 if (out && (outlen >= size)) {
3443 memset (out, 0, size);
3444 }
3445 }
3446 return TRUE;
3447 }
3448
3449 /*****************************************************************************
3450 * WINSPOOL_GetStringFromReg
3451 *
3452 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3453 * String is stored as unicode.
3454 */
3455 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3456 DWORD buflen, DWORD *needed)
3457 {
3458 DWORD sz = buflen, type;
3459 LONG ret;
3460
3461 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3462 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3463 WARN("Got ret = %d\n", ret);
3464 *needed = 0;
3465 return FALSE;
3466 }
3467 /* add space for terminating '\0' */
3468 sz += sizeof(WCHAR);
3469 *needed = sz;
3470
3471 if (ptr)
3472 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3473
3474 return TRUE;
3475 }
3476
3477 /*****************************************************************************
3478 * WINSPOOL_GetDefaultDevMode
3479 *
3480 * Get a default DevMode values for wineps.
3481 * FIXME - use ppd.
3482 */
3483
3484 static void WINSPOOL_GetDefaultDevMode(
3485 LPBYTE ptr,
3486 DWORD buflen, DWORD *needed)
3487 {
3488 DEVMODEW dm;
3489 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3490
3491 /* fill default DEVMODE - should be read from ppd... */
3492 ZeroMemory( &dm, sizeof(dm) );
3493 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3494 dm.dmSpecVersion = DM_SPECVERSION;
3495 dm.dmDriverVersion = 1;
3496 dm.dmSize = sizeof(DEVMODEW);
3497 dm.dmDriverExtra = 0;
3498 dm.dmFields =
3499 DM_ORIENTATION | DM_PAPERSIZE |
3500 DM_PAPERLENGTH | DM_PAPERWIDTH |
3501 DM_SCALE |
3502 DM_COPIES |
3503 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3504 DM_YRESOLUTION | DM_TTOPTION;
3505
3506 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3507 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3508 dm.u1.s1.dmPaperLength = 2970;
3509 dm.u1.s1.dmPaperWidth = 2100;
3510
3511 dm.u1.s1.dmScale = 100;
3512 dm.u1.s1.dmCopies = 1;
3513 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3514 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3515 /* dm.dmColor */
3516 /* dm.dmDuplex */
3517 dm.dmYResolution = 300; /* 300dpi */
3518 dm.dmTTOption = DMTT_BITMAP;
3519 /* dm.dmCollate */
3520 /* dm.dmFormName */
3521 /* dm.dmLogPixels */
3522 /* dm.dmBitsPerPel */
3523 /* dm.dmPelsWidth */
3524 /* dm.dmPelsHeight */
3525 /* dm.u2.dmDisplayFlags */
3526 /* dm.dmDisplayFrequency */
3527 /* dm.dmICMMethod */
3528 /* dm.dmICMIntent */
3529 /* dm.dmMediaType */
3530 /* dm.dmDitherType */
3531 /* dm.dmReserved1 */
3532 /* dm.dmReserved2 */
3533 /* dm.dmPanningWidth */
3534 /* dm.dmPanningHeight */
3535
3536 if(buflen >= sizeof(DEVMODEW))
3537 memcpy(ptr, &dm, sizeof(DEVMODEW));
3538 *needed = sizeof(DEVMODEW);
3539 }
3540
3541 /*****************************************************************************
3542 * WINSPOOL_GetDevModeFromReg
3543 *
3544 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3545 * DevMode is stored either as unicode or ascii.
3546 */
3547 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3548 LPBYTE ptr,
3549 DWORD buflen, DWORD *needed)
3550 {
3551 DWORD sz = buflen, type;
3552 LONG ret;
3553
3554 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3555 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3556 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3557 if (sz < sizeof(DEVMODEA))
3558 {
3559 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3560 return FALSE;
3561 }
3562 /* ensures that dmSize is not erratically bogus if registry is invalid */
3563 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3564 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3565 sz += (CCHDEVICENAME + CCHFORMNAME);
3566 if (ptr && (buflen >= sz)) {
3567 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3568 memcpy(ptr, dmW, sz);
3569 HeapFree(GetProcessHeap(),0,dmW);
3570 }
3571 *needed = sz;
3572 return TRUE;
3573 }
3574
3575 /*********************************************************************
3576 * WINSPOOL_GetPrinter_1
3577 *
3578 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3579 */
3580 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3581 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3582 {
3583 DWORD size, left = cbBuf;
3584 BOOL space = (cbBuf > 0);
3585 LPBYTE ptr = buf;
3586
3587 *pcbNeeded = 0;
3588
3589 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3590 if(space && size <= left) {
3591 pi1->pName = (LPWSTR)ptr;
3592 ptr += size;
3593 left -= size;
3594 } else
3595 space = FALSE;
3596 *pcbNeeded += size;
3597 }
3598
3599 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3600 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3601 if(space && size <= left) {
3602 pi1->pDescription = (LPWSTR)ptr;
3603 ptr += size;
3604 left -= size;
3605 } else
3606 space = FALSE;
3607 *pcbNeeded += size;
3608 }
3609
3610 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3611 if(space && size <= left) {
3612 pi1->pComment = (LPWSTR)ptr;
3613 ptr += size;
3614 left -= size;
3615 } else
3616 space = FALSE;
3617 *pcbNeeded += size;
3618 }
3619
3620 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3621
3622 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3623 memset(pi1, 0, sizeof(*pi1));
3624
3625 return space;
3626 }
3627 /*********************************************************************
3628 * WINSPOOL_GetPrinter_2
3629 *
3630 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3631 */
3632 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3633 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3634 {
3635 DWORD size, left = cbBuf;
3636 BOOL space = (cbBuf > 0);
3637 LPBYTE ptr = buf;
3638
3639 *pcbNeeded = 0;
3640
3641 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3642 if(space && size <= left) {
3643 pi2->pPrinterName = (LPWSTR)ptr;
3644 ptr += size;
3645 left -= size;
3646 } else
3647 space = FALSE;
3648 *pcbNeeded += size;
3649 }
3650 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
3651 if(space && size <= left) {
3652 pi2->pShareName = (LPWSTR)ptr;
3653 ptr += size;
3654 left -= size;
3655 } else
3656 space = FALSE;
3657 *pcbNeeded += size;
3658 }
3659 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3660 if(space && size <= left) {
3661 pi2->pPortName = (LPWSTR)ptr;
3662 ptr += size;
3663 left -= size;
3664 } else
3665 space = FALSE;
3666 *pcbNeeded += size;
3667 }
3668 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
3669 if(space && size <= left) {
3670 pi2->pDriverName = (LPWSTR)ptr;
3671 ptr += size;
3672 left -= size;
3673 } else
3674 space = FALSE;
3675 *pcbNeeded += size;
3676 }
3677 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3678 if(space && size <= left) {
3679 pi2->pComment = (LPWSTR)ptr;
3680 ptr += size;
3681 left -= size;
3682 } else
3683 space = FALSE;
3684 *pcbNeeded += size;
3685 }
3686 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
3687 if(space && size <= left) {
3688 pi2->pLocation = (LPWSTR)ptr;
3689 ptr += size;
3690 left -= size;
3691 } else
3692 space = FALSE;
3693 *pcbNeeded += size;
3694 }
3695 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
3696 if(space && size <= left) {
3697 pi2->pDevMode = (LPDEVMODEW)ptr;
3698 ptr += size;
3699 left -= size;
3700 } else
3701 space = FALSE;
3702 *pcbNeeded += size;
3703 }
3704 else
3705 {
3706 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
3707 if(space && size <= left) {
3708 pi2->pDevMode = (LPDEVMODEW)ptr;
3709 ptr += size;
3710 left -= size;
3711 } else
3712 space = FALSE;
3713 *pcbNeeded += size;
3714 }
3715 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
3716 if(space && size <= left) {
3717 pi2->pSepFile = (LPWSTR)ptr;
3718 ptr += size;
3719 left -= size;
3720 } else
3721 space = FALSE;
3722 *pcbNeeded += size;
3723 }
3724 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
3725 if(space && size <= left) {
3726 pi2->pPrintProcessor = (LPWSTR)ptr;
3727 ptr += size;
3728 left -= size;
3729 } else
3730 space = FALSE;
3731 *pcbNeeded += size;
3732 }
3733 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
3734 if(space && size <= left) {
3735 pi2->pDatatype = (LPWSTR)ptr;
3736 ptr += size;
3737 left -= size;
3738 } else
3739 space = FALSE;
3740 *pcbNeeded += size;
3741 }
3742 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
3743 if(space && size <= left) {
3744 pi2->pParameters = (LPWSTR)ptr;
3745 ptr += size;
3746 left -= size;
3747 } else
3748 space = FALSE;
3749 *pcbNeeded += size;
3750 }
3751 if(pi2) {
3752 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3753 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3754 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3755 "Default Priority");
3756 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3757 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3758 }
3759
3760 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3761 memset(pi2, 0, sizeof(*pi2));
3762
3763 return space;
3764 }
3765
3766 /*********************************************************************
3767 * WINSPOOL_GetPrinter_4
3768 *
3769 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3770 */
3771 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3772 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3773 {
3774 DWORD size, left = cbBuf;
3775 BOOL space = (cbBuf > 0);
3776 LPBYTE ptr = buf;
3777
3778 *pcbNeeded = 0;
3779
3780 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3781 if(space && size <= left) {
3782 pi4->pPrinterName = (LPWSTR)ptr;
3783 ptr += size;
3784 left -= size;
3785 } else
3786 space = FALSE;
3787 *pcbNeeded += size;
3788 }
3789 if(pi4) {
3790 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3791 }
3792
3793 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3794 memset(pi4, 0, sizeof(*pi4));
3795
3796 return space;
3797 }
3798
3799 /*********************************************************************
3800 * WINSPOOL_GetPrinter_5
3801 *
3802 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3803 */
3804 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3805 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3806 {
3807 DWORD size, left = cbBuf;
3808 BOOL space = (cbBuf > 0);
3809 LPBYTE ptr = buf;
3810
3811 *pcbNeeded = 0;
3812
3813 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3814 if(space && size <= left) {
3815 pi5->pPrinterName = (LPWSTR)ptr;
3816 ptr += size;
3817 left -= size;
3818 } else
3819 space = FALSE;
3820 *pcbNeeded += size;
3821 }
3822 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3823 if(space && size <= left) {
3824 pi5->pPortName = (LPWSTR)ptr;
3825 ptr += size;
3826 left -= size;
3827 } else
3828 space = FALSE;
3829 *pcbNeeded += size;
3830 }
3831 if(pi5) {
3832 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3833 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3834 "dnsTimeout");
3835 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3836 "txTimeout");
3837 }
3838
3839 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3840 memset(pi5, 0, sizeof(*pi5));
3841
3842 return space;
3843 }
3844
3845 /*********************************************************************
3846 * WINSPOOL_GetPrinter_7
3847 *
3848 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3849 */
3850 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3851 DWORD cbBuf, LPDWORD pcbNeeded)
3852 {
3853 DWORD size, left = cbBuf;
3854 BOOL space = (cbBuf > 0);
3855 LPBYTE ptr = buf;
3856
3857 *pcbNeeded = 0;
3858
3859 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
3860 {
3861 ptr = NULL;
3862 size = sizeof(pi7->pszObjectGUID);
3863 }
3864 if (space && size <= left) {
3865 pi7->pszObjectGUID = (LPWSTR)ptr;
3866 ptr += size;
3867 left -= size;
3868 } else
3869 space = FALSE;
3870 *pcbNeeded += size;
3871 if (pi7) {
3872 /* We do not have a Directory Service */
3873 pi7->dwAction = DSPRINT_UNPUBLISH;
3874 }
3875
3876 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3877 memset(pi7, 0, sizeof(*pi7));
3878
3879 return space;
3880 }
3881
3882 /*********************************************************************
3883 * WINSPOOL_GetPrinter_9
3884 *
3885 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3886 */
3887 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3888 DWORD cbBuf, LPDWORD pcbNeeded)
3889 {
3890 DWORD size;
3891 BOOL space = (cbBuf > 0);
3892
3893 *pcbNeeded = 0;
3894
3895 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
3896 if(space && size <= cbBuf) {
3897 pi9->pDevMode = (LPDEVMODEW)buf;
3898 } else
3899 space = FALSE;
3900 *pcbNeeded += size;
3901 }
3902 else
3903 {
3904 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
3905 if(space && size <= cbBuf) {
3906 pi9->pDevMode = (LPDEVMODEW)buf;
3907 } else
3908 space = FALSE;
3909 *pcbNeeded += size;
3910 }
3911
3912 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3913 memset(pi9, 0, sizeof(*pi9));
3914
3915 return space;
3916 }
3917
3918 /*****************************************************************************
3919 * GetPrinterW [WINSPOOL.@]
3920 */
3921 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3922 DWORD cbBuf, LPDWORD pcbNeeded)
3923 {
3924 DWORD size, needed = 0, err;
3925 LPBYTE ptr = NULL;
3926 HKEY hkeyPrinter;
3927 BOOL ret;
3928
3929 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3930
3931 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
3932 if (err)
3933 {
3934 SetLastError( err );
3935 return FALSE;
3936 }
3937
3938 switch(Level) {
3939 case 2:
3940 {
3941 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3942
3943 size = sizeof(PRINTER_INFO_2W);
3944 if(size <= cbBuf) {
3945 ptr = pPrinter + size;
3946 cbBuf -= size;
3947 memset(pPrinter, 0, size);
3948 } else {
3949 pi2 = NULL;
3950 cbBuf = 0;
3951 }
3952 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
3953 needed += size;
3954 break;
3955 }
3956
3957 case 4:
3958 {
3959 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3960
3961 size = sizeof(PRINTER_INFO_4W);
3962 if(size <= cbBuf) {
3963 ptr = pPrinter + size;
3964 cbBuf -= size;
3965 memset(pPrinter, 0, size);
3966 } else {
3967 pi4 = NULL;
3968 cbBuf = 0;
3969 }
3970 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
3971 needed += size;
3972 break;
3973 }
3974
3975
3976 case 5:
3977 {
3978 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3979
3980 size = sizeof(PRINTER_INFO_5W);
3981 if(size <= cbBuf) {
3982 ptr = pPrinter + size;
3983 cbBuf -= size;
3984 memset(pPrinter, 0, size);
3985 } else {
3986 pi5 = NULL;
3987 cbBuf = 0;
3988 }
3989
3990 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
3991 needed += size;
3992 break;
3993 }
3994
3995
3996 case 6:
3997 {
3998 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
3999
4000 size = sizeof(PRINTER_INFO_6);
4001 if (size <= cbBuf) {
4002 /* FIXME: We do not update the status yet */
4003 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
4004 ret = TRUE;
4005 } else {
4006 ret = FALSE;
4007 }
4008
4009 needed += size;
4010 break;
4011 }
4012
4013 case 7:
4014 {
4015 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4016
4017 size = sizeof(PRINTER_INFO_7W);
4018 if (size <= cbBuf) {
4019 ptr = pPrinter + size;
4020 cbBuf -= size;
4021 memset(pPrinter, 0, size);
4022 } else {
4023 pi7 = NULL;
4024 cbBuf = 0;
4025 }
4026
4027 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
4028 needed += size;
4029 break;
4030 }
4031
4032
4033 case 8:
4034 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4035 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4036 /* fall through */
4037 case 9:
4038 {
4039 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4040
4041 size = sizeof(PRINTER_INFO_9W);
4042 if(size <= cbBuf) {
4043 ptr = pPrinter + size;
4044 cbBuf -= size;
4045 memset(pPrinter, 0, size);
4046 } else {
4047 pi9 = NULL;
4048 cbBuf = 0;
4049 }
4050
4051 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
4052 needed += size;
4053 break;
4054 }
4055
4056
4057 default:
4058 FIXME("Unimplemented level %d\n", Level);
4059 SetLastError(ERROR_INVALID_LEVEL);
4060 RegCloseKey(hkeyPrinter);
4061 return FALSE;
4062 }
4063
4064 RegCloseKey(hkeyPrinter);
4065
4066 TRACE("returning %d needed = %d\n", ret, needed);
4067 if(pcbNeeded) *pcbNeeded = needed;
4068 if(!ret)
4069 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4070 return ret;
4071 }
4072
4073 /*****************************************************************************
4074 * GetPrinterA [WINSPOOL.@]
4075 */
4076 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4077 DWORD cbBuf, LPDWORD pcbNeeded)
4078 {
4079 BOOL ret;
4080 LPBYTE buf = NULL;
4081
4082 if (cbBuf)
4083 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4084
4085 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4086 if (ret)
4087 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4088 HeapFree(GetProcessHeap(), 0, buf);
4089
4090 return ret;
4091 }
4092
4093 /*****************************************************************************
4094 * WINSPOOL_EnumPrintersW
4095 *
4096 * Implementation of EnumPrintersW
4097 */
4098 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4099 DWORD dwLevel, LPBYTE lpbPrinters,
4100 DWORD cbBuf, LPDWORD lpdwNeeded,
4101 LPDWORD lpdwReturned)
4102
4103 {
4104 HKEY hkeyPrinters, hkeyPrinter;
4105 WCHAR PrinterName[255];
4106 DWORD needed = 0, number = 0;
4107 DWORD used, i, left;
4108 PBYTE pi, buf;
4109
4110 if(lpbPrinters)
4111 memset(lpbPrinters, 0, cbBuf);
4112 if(lpdwReturned)
4113 *lpdwReturned = 0;
4114 if(lpdwNeeded)
4115 *lpdwNeeded = 0;
4116
4117 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4118 if(dwType == PRINTER_ENUM_DEFAULT)
4119 return TRUE;
4120
4121 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4122 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4123 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4124 if (!dwType) {
4125 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4126 return TRUE;
4127 }
4128
4129 }
4130
4131 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4132 FIXME("dwType = %08x\n", dwType);
4133 SetLastError(ERROR_INVALID_FLAGS);
4134 return FALSE;
4135 }
4136
4137 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4138 ERROR_SUCCESS) {
4139 ERR("Can't create Printers key\n");
4140 return FALSE;
4141 }
4142
4143 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4144 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4145 RegCloseKey(hkeyPrinters);
4146 ERR("Can't query Printers key\n");
4147 return FALSE;
4148 }
4149 TRACE("Found %d printers\n", number);
4150
4151 switch(dwLevel) {
4152 case 1:
4153 used = number * sizeof(PRINTER_INFO_1W);
4154 break;
4155 case 2:
4156 used = number * sizeof(PRINTER_INFO_2W);
4157 break;
4158 case 4:
4159 used = number * sizeof(PRINTER_INFO_4W);
4160 break;
4161 case 5:
4162 used = number * sizeof(PRINTER_INFO_5W);
4163 break;
4164
4165 default:
4166 SetLastError(ERROR_INVALID_LEVEL);
4167 RegCloseKey(hkeyPrinters);
4168 return FALSE;
4169 }
4170 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4171
4172 for(i = 0; i < number; i++) {
4173 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4174 ERROR_SUCCESS) {
4175 ERR("Can't enum key number %d\n", i);
4176 RegCloseKey(hkeyPrinters);
4177 return FALSE;
4178 }
4179 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4180 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4181 ERROR_SUCCESS) {
4182 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4183 RegCloseKey(hkeyPrinters);
4184 return FALSE;
4185 }
4186
4187 if(cbBuf > used) {
4188 buf = lpbPrinters + used;
4189 left = cbBuf - used;
4190 } else {
4191 buf = NULL;
4192 left = 0;
4193 }
4194
4195 switch(dwLevel) {
4196 case 1:
4197 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4198 left, &needed);
4199 used += needed;
4200 if(pi) pi += sizeof(PRINTER_INFO_1W);
4201 break;
4202 case 2:
4203 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4204 left, &needed);
4205 used += needed;
4206 if(pi) pi += sizeof(PRINTER_INFO_2W);
4207 break;
4208 case 4:
4209 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4210 left, &needed);
4211 used += needed;
4212 if(pi) pi += sizeof(PRINTER_INFO_4W);
4213 break;
4214 case 5:
4215 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4216 left, &needed);
4217 used += needed;
4218 if(pi) pi += sizeof(PRINTER_INFO_5W);
4219 break;
4220 default:
4221 ERR("Shouldn't be here!\n");
4222 RegCloseKey(hkeyPrinter);
4223 RegCloseKey(hkeyPrinters);
4224 return FALSE;
4225 }
4226 RegCloseKey(hkeyPrinter);
4227 }
4228 RegCloseKey(hkeyPrinters);
4229
4230 if(lpdwNeeded)
4231 *lpdwNeeded = used;
4232
4233 if(used > cbBuf) {
4234 if(lpbPrinters)
4235 memset(lpbPrinters, 0, cbBuf);
4236 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4237 return FALSE;
4238 }
4239 if(lpdwReturned)
4240 *lpdwReturned = number;
4241 SetLastError(ERROR_SUCCESS);
4242 return TRUE;
4243 }
4244
4245
4246 /******************************************************************
4247 * EnumPrintersW [WINSPOOL.@]
4248 *
4249 * Enumerates the available printers, print servers and print
4250 * providers, depending on the specified flags, name and level.
4251 *
4252 * RETURNS:
4253 *
4254 * If level is set to 1:
4255 * Returns an array of PRINTER_INFO_1 data structures in the
4256 * lpbPrinters buffer.
4257 *
4258 * If level is set to 2:
4259 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4260 * Returns an array of PRINTER_INFO_2 data structures in the
4261 * lpbPrinters buffer. Note that according to MSDN also an
4262 * OpenPrinter should be performed on every remote printer.
4263 *
4264 * If level is set to 4 (officially WinNT only):
4265 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4266 * Fast: Only the registry is queried to retrieve printer names,
4267 * no connection to the driver is made.
4268 * Returns an array of PRINTER_INFO_4 data structures in the
4269 * lpbPrinters buffer.
4270 *
4271 * If level is set to 5 (officially WinNT4/Win9x only):
4272 * Fast: Only the registry is queried to retrieve printer names,
4273 * no connection to the driver is made.
4274 * Returns an array of PRINTER_INFO_5 data structures in the
4275 * lpbPrinters buffer.
4276 *
4277 * If level set to 3 or 6+:
4278 * returns zero (failure!)
4279 *
4280 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4281 * for information.
4282 *
4283 * BUGS:
4284 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4285 * - Only levels 2, 4 and 5 are implemented at the moment.
4286 * - 16-bit printer drivers are not enumerated.
4287 * - Returned amount of bytes used/needed does not match the real Windoze
4288 * implementation (as in this implementation, all strings are part
4289 * of the buffer, whereas Win32 keeps them somewhere else)
4290 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4291 *
4292 * NOTE:
4293 * - In a regular Wine installation, no registry settings for printers
4294 * exist, which makes this function return an empty list.
4295 */
4296 BOOL WINAPI EnumPrintersW(
4297 DWORD dwType, /* [in] Types of print objects to enumerate */
4298 LPWSTR lpszName, /* [in] name of objects to enumerate */
4299 DWORD dwLevel, /* [in] type of printer info structure */
4300 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4301 DWORD cbBuf, /* [in] max size of buffer in bytes */
4302 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4303 LPDWORD lpdwReturned /* [out] number of entries returned */
4304 )
4305 {
4306 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4307 lpdwNeeded, lpdwReturned);
4308 }
4309
4310 /******************************************************************
4311 * EnumPrintersA [WINSPOOL.@]
4312 *
4313 * See EnumPrintersW
4314 *
4315 */
4316 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4317 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4318 {
4319 BOOL ret;
4320 UNICODE_STRING pNameU;
4321 LPWSTR pNameW;
4322 LPBYTE pPrintersW;
4323
4324 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4325 pPrinters, cbBuf, pcbNeeded, pcReturned);
4326
4327 pNameW = asciitounicode(&pNameU, pName);
4328
4329 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4330 MS Office need this */
4331 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4332
4333 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4334
4335 RtlFreeUnicodeString(&pNameU);
4336 if (ret) {
4337 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4338 }
4339 HeapFree(GetProcessHeap(), 0, pPrintersW);
4340 return ret;
4341 }
4342
4343 /*****************************************************************************
4344 * WINSPOOL_GetDriverInfoFromReg [internal]
4345 *
4346 * Enters the information from the registry into the DRIVER_INFO struct
4347 *
4348 * RETURNS
4349 * zero if the printer driver does not exist in the registry
4350 * (only if Level > 1) otherwise nonzero
4351 */
4352 static BOOL WINSPOOL_GetDriverInfoFromReg(
4353 HKEY hkeyDrivers,
4354 LPWSTR DriverName,
4355 const printenv_t * env,
4356 DWORD Level,
4357 LPBYTE ptr, /* DRIVER_INFO */
4358 LPBYTE pDriverStrings, /* strings buffer */
4359 DWORD cbBuf, /* size of string buffer */
4360 LPDWORD pcbNeeded) /* space needed for str. */
4361 {
4362 DWORD size, tmp;
4363 HKEY hkeyDriver;
4364 WCHAR driverdir[MAX_PATH];
4365 DWORD dirlen;
4366 LPBYTE strPtr = pDriverStrings;
4367 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4368
4369 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4370 debugstr_w(DriverName), env,
4371 Level, di, pDriverStrings, cbBuf);
4372
4373 if (di) ZeroMemory(di, di_sizeof[Level]);
4374
4375 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4376 if (*pcbNeeded <= cbBuf)
4377 strcpyW((LPWSTR)strPtr, DriverName);
4378
4379 /* pName for level 1 has a different offset! */
4380 if (Level == 1) {
4381 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4382 return TRUE;
4383 }
4384
4385 /* .cVersion and .pName for level > 1 */
4386 if (di) {
4387 di->cVersion = env->driverversion;
4388 di->pName = (LPWSTR) strPtr;
4389 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4390 }
4391
4392 /* Reserve Space for the largest subdir and a Backslash*/
4393 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4394 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4395 /* Should never Fail */
4396 return FALSE;
4397 }
4398 lstrcatW(driverdir, env->versionsubdir);
4399 lstrcatW(driverdir, backslashW);
4400
4401 /* dirlen must not include the terminating zero */
4402 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4403
4404 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4405 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4406 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4407 return FALSE;
4408 }
4409
4410 /* pEnvironment */
4411 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4412
4413 *pcbNeeded += size;
4414 if (*pcbNeeded <= cbBuf) {
4415 lstrcpyW((LPWSTR)strPtr, env->envname);
4416 if (di) di->pEnvironment = (LPWSTR)strPtr;
4417 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4418 }
4419
4420 /* .pDriverPath is the Graphics rendering engine.
4421 The full Path is required to avoid a crash in some apps */
4422 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4423 *pcbNeeded += size;
4424 if (*pcbNeeded <= cbBuf)
4425 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4426
4427 if (di) di->pDriverPath = (LPWSTR)strPtr;
4428 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4429 }
4430
4431 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4432 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4433 *pcbNeeded += size;
4434 if (*pcbNeeded <= cbBuf)
4435 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4436
4437 if (di) di->pDataFile = (LPWSTR)strPtr;
4438 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4439 }
4440
4441 /* .pConfigFile is the Driver user Interface */
4442 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4443 *pcbNeeded += size;
4444 if (*pcbNeeded <= cbBuf)
4445 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4446
4447 if (di) di->pConfigFile = (LPWSTR)strPtr;
4448 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4449 }
4450
4451 if (Level == 2 ) {
4452 RegCloseKey(hkeyDriver);
4453 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4454 return TRUE;
4455 }
4456
4457 if (Level == 5 ) {
4458 RegCloseKey(hkeyDriver);
4459 FIXME("level 5: incomplete\n");
4460 return TRUE;
4461 }
4462
4463 /* .pHelpFile */
4464 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4465 *pcbNeeded += size;
4466 if (*pcbNeeded <= cbBuf)
4467 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4468
4469 if (di) di->pHelpFile = (LPWSTR)strPtr;
4470 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4471 }
4472
4473 /* .pDependentFiles */
4474 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4475 *pcbNeeded += size;
4476 if (*pcbNeeded <= cbBuf)
4477 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4478
4479 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4480 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4481 }
4482 else if (GetVersion() & 0x80000000) {
4483 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4484 size = 2 * sizeof(WCHAR);
4485 *pcbNeeded += size;
4486 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4487
4488 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4489 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4490 }
4491
4492 /* .pMonitorName is the optional Language Monitor */
4493 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4494 *pcbNeeded += size;
4495 if (*pcbNeeded <= cbBuf)
4496 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4497
4498 if (di) di->pMonitorName = (LPWSTR)strPtr;
4499 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4500 }
4501
4502 /* .pDefaultDataType */
4503 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4504 *pcbNeeded += size;
4505 if(*pcbNeeded <= cbBuf)
4506 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4507
4508 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4509 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4510 }
4511
4512 if (Level == 3 ) {
4513 RegCloseKey(hkeyDriver);
4514 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4515 return TRUE;
4516 }
4517
4518 /* .pszzPreviousNames */
4519 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4520 *pcbNeeded += size;
4521 if(*pcbNeeded <= cbBuf)
4522 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4523
4524 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4525 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4526 }
4527
4528 if (Level == 4 ) {
4529 RegCloseKey(hkeyDriver);
4530 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4531 return TRUE;
4532 }
4533
4534 /* support is missing, but not important enough for a FIXME */
4535 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4536
4537 /* .pszMfgName */
4538 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
4539 *pcbNeeded += size;
4540 if(*pcbNeeded <= cbBuf)
4541 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
4542
4543 if (di) di->pszMfgName = (LPWSTR)strPtr;
4544 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4545 }
4546
4547 /* .pszOEMUrl */
4548 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
4549 *pcbNeeded += size;
4550 if(*pcbNeeded <= cbBuf)
4551 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
4552
4553 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4554 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4555 }
4556
4557 /* .pszHardwareID */
4558 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
4559 *pcbNeeded += size;
4560 if(*pcbNeeded <= cbBuf)
4561 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
4562
4563 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4564 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4565 }
4566
4567 /* .pszProvider */
4568 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
4569 *pcbNeeded += size;
4570 if(*pcbNeeded <= cbBuf)
4571 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
4572
4573 if (di) di->pszProvider = (LPWSTR)strPtr;
4574 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4575 }
4576
4577 if (Level == 6 ) {
4578 RegCloseKey(hkeyDriver);
4579 return TRUE;
4580 }
4581
4582 /* support is missing, but not important enough for a FIXME */
4583 TRACE("level 8: incomplete\n");
4584
4585 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4586 RegCloseKey(hkeyDriver);
4587 return TRUE;
4588 }
4589
4590 /*****************************************************************************
4591 * GetPrinterDriverW [WINSPOOL.@]
4592 */
4593 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4594 DWORD Level, LPBYTE pDriverInfo,
4595 DWORD cbBuf, LPDWORD pcbNeeded)
4596 {
4597 LPCWSTR name;
4598 WCHAR DriverName[100];
4599 DWORD ret, type, size, needed = 0;
4600 LPBYTE ptr = NULL;
4601 HKEY hkeyPrinter, hkeyDrivers;
4602 const printenv_t * env;
4603
4604 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4605 Level,pDriverInfo,cbBuf, pcbNeeded);
4606
4607 if (cbBuf > 0)
4608 ZeroMemory(pDriverInfo, cbBuf);
4609
4610 if (!(name = get_opened_printer_name(hPrinter))) {
4611 SetLastError(ERROR_INVALID_HANDLE);
4612 return FALSE;
4613 }
4614
4615 if (Level < 1 || Level == 7 || Level > 8) {
4616 SetLastError(ERROR_INVALID_LEVEL);
4617 return FALSE;
4618 }
4619
4620 env = validate_envW(pEnvironment);
4621 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4622
4623 ret = open_printer_reg_key( name, &hkeyPrinter );
4624 if (ret)
4625 {
4626 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
4627 SetLastError( ret );
4628 return FALSE;
4629 }
4630
4631 size = sizeof(DriverName);
4632 DriverName[0] = 0;
4633 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4634 (LPBYTE)DriverName, &size);
4635 RegCloseKey(hkeyPrinter);
4636 if(ret != ERROR_SUCCESS) {
4637 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4638 return FALSE;
4639 }
4640
4641 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4642 if(!hkeyDrivers) {
4643 ERR("Can't create Drivers key\n");
4644 return FALSE;
4645 }
4646
4647 size = di_sizeof[Level];
4648 if ((size <= cbBuf) && pDriverInfo)
4649 ptr = pDriverInfo + size;
4650
4651 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4652 env, Level, pDriverInfo, ptr,
4653 (cbBuf < size) ? 0 : cbBuf - size,
4654 &needed)) {
4655 RegCloseKey(hkeyDrivers);
4656 return FALSE;
4657 }
4658
4659 RegCloseKey(hkeyDrivers);
4660
4661 if(pcbNeeded) *pcbNeeded = size + needed;
4662 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4663 if(cbBuf >= size + needed) return TRUE;
4664 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4665 return FALSE;
4666 }
4667
4668 /*****************************************************************************
4669 * GetPrinterDriverA [WINSPOOL.@]
4670 */
4671 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4672 DWORD Level, LPBYTE pDriverInfo,
4673 DWORD cbBuf, LPDWORD pcbNeeded)
4674 {
4675 BOOL ret;
4676 UNICODE_STRING pEnvW;
4677 PWSTR pwstrEnvW;
4678 LPBYTE buf = NULL;
4679
4680 if (cbBuf)
4681 {
4682 ZeroMemory(pDriverInfo, cbBuf);
4683 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4684 }
4685
4686 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4687 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4688 cbBuf, pcbNeeded);
4689 if (ret)
4690 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4691
4692 HeapFree(GetProcessHeap(), 0, buf);
4693
4694 RtlFreeUnicodeString(&pEnvW);
4695 return ret;
4696 }
4697
4698 /*****************************************************************************
4699 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4700 *
4701 * Return the PATH for the Printer-Drivers (UNICODE)
4702 *
4703 * PARAMS
4704 * pName [I] Servername (NT only) or NULL (local Computer)
4705 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4706 * Level [I] Structure-Level (must be 1)
4707 * pDriverDirectory [O] PTR to Buffer that receives the Result
4708 * cbBuf [I] Size of Buffer at pDriverDirectory
4709 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4710 * required for pDriverDirectory
4711 *
4712 * RETURNS
4713 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4714 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4715 * if cbBuf is too small
4716 *
4717 * Native Values returned in pDriverDirectory on Success:
4718 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4719 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4720 *| win9x(Windows 4.0): "%winsysdir%"
4721 *
4722 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4723 *
4724 * FIXME
4725 *- Only NULL or "" is supported for pName
4726 *
4727 */
4728 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4729 DWORD Level, LPBYTE pDriverDirectory,
4730 DWORD cbBuf, LPDWORD pcbNeeded)
4731 {
4732 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4733 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4734
4735 if ((backend == NULL) && !load_backend()) return FALSE;
4736
4737 if (Level != 1) {
4738 /* (Level != 1) is ignored in win9x */
4739 SetLastError(ERROR_INVALID_LEVEL);
4740 return FALSE;
4741 }
4742 if (pcbNeeded == NULL) {
4743 /* (pcbNeeded == NULL) is ignored in win9x */
4744 SetLastError(RPC_X_NULL_REF_POINTER);
4745 return FALSE;
4746 }
4747
4748 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4749 pDriverDirectory, cbBuf, pcbNeeded);
4750
4751 }
4752
4753
4754 /*****************************************************************************
4755 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4756 *
4757 * Return the PATH for the Printer-Drivers (ANSI)
4758 *
4759 * See GetPrinterDriverDirectoryW.
4760 *
4761 * NOTES
4762 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4763 *
4764 */
4765 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4766 DWORD Level, LPBYTE pDriverDirectory,
4767 DWORD cbBuf, LPDWORD pcbNeeded)
4768 {
4769 UNICODE_STRING nameW, environmentW;
4770 BOOL ret;
4771 DWORD pcbNeededW;
4772 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4773 WCHAR *driverDirectoryW = NULL;
4774
4775 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4776 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4777
4778 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4779
4780 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4781 else nameW.Buffer = NULL;
4782 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4783 else environmentW.Buffer = NULL;
4784
4785 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4786 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4787 if (ret) {
4788 DWORD needed;
4789 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4790 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4791 if(pcbNeeded)
4792 *pcbNeeded = needed;
4793 ret = (needed <= cbBuf) ? TRUE : FALSE;
4794 } else
4795 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4796
4797 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4798
4799 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4800 RtlFreeUnicodeString(&environmentW);
4801 RtlFreeUnicodeString(&nameW);
4802
4803 return ret;
4804 }
4805
4806 /*****************************************************************************
4807 * AddPrinterDriverA [WINSPOOL.@]
4808 *
4809 * See AddPrinterDriverW.
4810 *
4811 */
4812 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4813 {
4814 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4815 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4816 }
4817
4818 /******************************************************************************
4819 * AddPrinterDriverW (WINSPOOL.@)
4820 *
4821 * Install a Printer Driver
4822 *
4823 * PARAMS
4824 * pName [I] Servername or NULL (local Computer)
4825 * level [I] Level for the supplied DRIVER_INFO_*W struct
4826 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4827 *
4828 * RESULTS
4829 * Success: TRUE
4830 * Failure: FALSE
4831 *
4832 */
4833 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4834 {
4835 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4836 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4837 }
4838
4839 /*****************************************************************************
4840 * AddPrintProcessorA [WINSPOOL.@]
4841 */
4842 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4843 LPSTR pPrintProcessorName)
4844 {
4845 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4846 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4847 return FALSE;
4848 }
4849
4850 /*****************************************************************************
4851 * AddPrintProcessorW [WINSPOOL.@]
4852 */
4853 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4854 LPWSTR pPrintProcessorName)
4855 {
4856 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4857 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4858 return TRUE;
4859 }
4860
4861 /*****************************************************************************
4862 * AddPrintProvidorA [WINSPOOL.@]
4863 */
4864 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4865 {
4866 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4867 return FALSE;
4868 }
4869
4870 /*****************************************************************************
4871 * AddPrintProvidorW [WINSPOOL.@]
4872 */
4873 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4874 {
4875 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4876 return FALSE;
4877 }
4878
4879 /*****************************************************************************
4880 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4881 */
4882 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4883 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4884 {
4885 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4886 pDevModeOutput, pDevModeInput);
4887 return 0;
4888 }
4889
4890 /*****************************************************************************
4891 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4892 */
4893 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4894 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4895 {
4896 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4897 pDevModeOutput, pDevModeInput);
4898 return 0;
4899 }
4900
4901 /*****************************************************************************
4902 * PrinterProperties [WINSPOOL.@]
4903 *
4904 * Displays a dialog to set the properties of the printer.
4905 *
4906 * RETURNS
4907 * nonzero on success or zero on failure
4908 *
4909 * BUGS
4910 * implemented as stub only
4911 */
4912 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4913 HANDLE hPrinter /* [in] handle to printer object */
4914 ){
4915 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4916 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4917 return FALSE;
4918 }
4919
4920 /*****************************************************************************
4921 * EnumJobsA [WINSPOOL.@]
4922 *
4923 */
4924 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4925 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4926 LPDWORD pcReturned)
4927 {
4928 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4929 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4930 );
4931 if(pcbNeeded) *pcbNeeded = 0;
4932 if(pcReturned) *pcReturned = 0;
4933 return FALSE;
4934 }
4935
4936
4937 /*****************************************************************************
4938 * EnumJobsW [WINSPOOL.@]
4939 *
4940 */
4941 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4942 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4943 LPDWORD pcReturned)
4944 {
4945 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4946 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4947 );
4948 if(pcbNeeded) *pcbNeeded = 0;
4949 if(pcReturned) *pcReturned = 0;
4950 return FALSE;
4951 }
4952
4953 /*****************************************************************************
4954 * WINSPOOL_EnumPrinterDrivers [internal]
4955 *
4956 * Delivers information about all printer drivers installed on the
4957 * localhost or a given server
4958 *
4959 * RETURNS
4960 * nonzero on success or zero on failure. If the buffer for the returned
4961 * information is too small the function will return an error
4962 *
4963 * BUGS
4964 * - only implemented for localhost, foreign hosts will return an error
4965 */
4966 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4967 DWORD Level, LPBYTE pDriverInfo,
4968 DWORD driver_index,
4969 DWORD cbBuf, LPDWORD pcbNeeded,
4970 LPDWORD pcFound, DWORD data_offset)
4971
4972 { HKEY hkeyDrivers;
4973 DWORD i, size = 0;
4974 const printenv_t * env;
4975
4976 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4977 debugstr_w(pName), debugstr_w(pEnvironment),
4978 Level, pDriverInfo, driver_index, cbBuf, data_offset);
4979
4980 env = validate_envW(pEnvironment);
4981 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4982
4983 *pcFound = 0;
4984
4985 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4986 if(!hkeyDrivers) {
4987 ERR("Can't open Drivers key\n");
4988 return FALSE;
4989 }
4990
4991 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
4992 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4993 RegCloseKey(hkeyDrivers);
4994 ERR("Can't query Drivers key\n");
4995 return FALSE;
4996 }
4997 TRACE("Found %d Drivers\n", *pcFound);
4998
4999 /* get size of single struct
5000 * unicode and ascii structure have the same size
5001 */
5002 size = di_sizeof[Level];
5003
5004 if (data_offset == 0)
5005 data_offset = size * (*pcFound);
5006 *pcbNeeded = data_offset;
5007
5008 for( i = 0; i < *pcFound; i++) {
5009 WCHAR DriverNameW[255];
5010 PBYTE table_ptr = NULL;
5011 PBYTE data_ptr = NULL;
5012 DWORD needed = 0;
5013
5014 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5015 != ERROR_SUCCESS) {
5016 ERR("Can't enum key number %d\n", i);
5017 RegCloseKey(hkeyDrivers);
5018 return FALSE;
5019 }
5020
5021 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
5022 table_ptr = pDriverInfo + (driver_index + i) * size;
5023 if (pDriverInfo && *pcbNeeded <= cbBuf)
5024 data_ptr = pDriverInfo + *pcbNeeded;
5025
5026 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5027 env, Level, table_ptr, data_ptr,
5028 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5029 &needed)) {
5030 RegCloseKey(hkeyDrivers);
5031 return FALSE;
5032 }
5033
5034 *pcbNeeded += needed;
5035 }
5036
5037 RegCloseKey(hkeyDrivers);
5038
5039 if(cbBuf < *pcbNeeded){
5040 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5041 return FALSE;
5042 }
5043
5044 return TRUE;
5045 }
5046
5047 /*****************************************************************************
5048 * EnumPrinterDriversW [WINSPOOL.@]
5049 *
5050 * see function EnumPrinterDrivers for RETURNS, BUGS
5051 */
5052 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5053 LPBYTE pDriverInfo, DWORD cbBuf,
5054 LPDWORD pcbNeeded, LPDWORD pcReturned)
5055 {
5056 static const WCHAR allW[] = {'a','l','l',0};
5057 BOOL ret;
5058 DWORD found;
5059
5060 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5061 {
5062 SetLastError(RPC_X_NULL_REF_POINTER);
5063 return FALSE;
5064 }
5065
5066 /* check for local drivers */
5067 if((pName) && (pName[0])) {
5068 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5069 SetLastError(ERROR_ACCESS_DENIED);
5070 return FALSE;
5071 }
5072
5073 /* check input parameter */
5074 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5075 SetLastError(ERROR_INVALID_LEVEL);
5076 return FALSE;
5077 }
5078
5079 if(pDriverInfo && cbBuf > 0)
5080 memset( pDriverInfo, 0, cbBuf);
5081
5082 /* Exception: pull all printers */
5083 if (pEnvironment && !strcmpW(pEnvironment, allW))
5084 {
5085 DWORD i, needed, bufsize = cbBuf;
5086 DWORD total_needed = 0;
5087 DWORD total_found = 0;
5088 DWORD data_offset;
5089
5090 /* Precompute the overall total; we need this to know
5091 where pointers end and data begins (i.e. data_offset) */
5092 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5093 {
5094 needed = found = 0;
5095 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5096 NULL, 0, 0, &needed, &found, 0);
5097 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5098 total_needed += needed;
5099 total_found += found;
5100 }
5101
5102 data_offset = di_sizeof[Level] * total_found;
5103
5104 *pcReturned = 0;
5105 *pcbNeeded = 0;
5106 total_found = 0;
5107 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5108 {
5109 needed = found = 0;
5110 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5111 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5112 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5113 else if (ret)
5114 *pcReturned += found;
5115 *pcbNeeded = needed;
5116 data_offset = needed;
5117 total_found += found;
5118 }
5119 return ret;
5120 }
5121
5122 /* Normal behavior */
5123 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5124 0, cbBuf, pcbNeeded, &found, 0);
5125 if (ret)
5126 *pcReturned = found;
5127
5128 return ret;
5129 }
5130
5131 /*****************************************************************************
5132 * EnumPrinterDriversA [WINSPOOL.@]
5133 *
5134 * see function EnumPrinterDrivers for RETURNS, BUGS
5135 */
5136 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5137 LPBYTE pDriverInfo, DWORD cbBuf,
5138 LPDWORD pcbNeeded, LPDWORD pcReturned)
5139 {
5140 BOOL ret;
5141 UNICODE_STRING pNameW, pEnvironmentW;
5142 PWSTR pwstrNameW, pwstrEnvironmentW;
5143 LPBYTE buf = NULL;
5144
5145 if (cbBuf)
5146 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5147
5148 pwstrNameW = asciitounicode(&pNameW, pName);
5149 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5150
5151 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5152 buf, cbBuf, pcbNeeded, pcReturned);
5153 if (ret)
5154 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5155
5156 HeapFree(GetProcessHeap(), 0, buf);
5157
5158 RtlFreeUnicodeString(&pNameW);
5159 RtlFreeUnicodeString(&pEnvironmentW);
5160
5161 return ret;
5162 }
5163
5164 /******************************************************************************
5165 * EnumPortsA (WINSPOOL.@)
5166 *
5167 * See EnumPortsW.
5168 *
5169 */
5170 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5171 LPDWORD pcbNeeded, LPDWORD pcReturned)
5172 {
5173 BOOL res;
5174 LPBYTE bufferW = NULL;
5175 LPWSTR nameW = NULL;
5176 DWORD needed = 0;
5177 DWORD numentries = 0;
5178 INT len;
5179
5180 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5181 cbBuf, pcbNeeded, pcReturned);
5182
5183 /* convert servername to unicode */
5184 if (pName) {
5185 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5186 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5187 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5188 }
5189 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5190 needed = cbBuf * sizeof(WCHAR);
5191 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5192 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5193
5194 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5195 if (pcbNeeded) needed = *pcbNeeded;
5196 /* HeapReAlloc return NULL, when bufferW was NULL */
5197 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5198 HeapAlloc(GetProcessHeap(), 0, needed);
5199
5200 /* Try again with the large Buffer */
5201 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5202 }
5203 needed = pcbNeeded ? *pcbNeeded : 0;
5204 numentries = pcReturned ? *pcReturned : 0;
5205
5206 /*
5207 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5208 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5209 */
5210 if (res) {
5211 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5212 DWORD entrysize = 0;
5213 DWORD index;
5214 LPSTR ptr;
5215 LPPORT_INFO_2W pi2w;
5216 LPPORT_INFO_2A pi2a;
5217
5218 needed = 0;
5219 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5220
5221 /* First pass: calculate the size for all Entries */
5222 pi2w = (LPPORT_INFO_2W) bufferW;
5223 pi2a = (LPPORT_INFO_2A) pPorts;
5224 index = 0;
5225 while (index < numentries) {
5226 index++;
5227 needed += entrysize; /* PORT_INFO_?A */
5228 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5229
5230 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5231 NULL, 0, NULL, NULL);
5232 if (Level > 1) {
5233 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5234 NULL, 0, NULL, NULL);
5235 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5236 NULL, 0, NULL, NULL);
5237 }
5238 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5239 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5240 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5241 }
5242
5243 /* check for errors and quit on failure */
5244 if (cbBuf < needed) {
5245 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5246 res = FALSE;
5247 goto cleanup;
5248 }
5249 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5250 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5251 cbBuf -= len ; /* free Bytes in the user-Buffer */
5252 pi2w = (LPPORT_INFO_2W) bufferW;
5253 pi2a = (LPPORT_INFO_2A) pPorts;
5254 index = 0;
5255 /* Second Pass: Fill the User Buffer (if we have one) */
5256 while ((index < numentries) && pPorts) {
5257 index++;
5258 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5259 pi2a->pPortName = ptr;
5260 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5261 ptr, cbBuf , NULL, NULL);
5262 ptr += len;
5263 cbBuf -= len;
5264 if (Level > 1) {
5265 pi2a->pMonitorName = ptr;
5266 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5267 ptr, cbBuf, NULL, NULL);
5268 ptr += len;
5269 cbBuf -= len;
5270
5271 pi2a->pDescription = ptr;
5272 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5273 ptr, cbBuf, NULL, NULL);
5274 ptr += len;
5275 cbBuf -= len;
5276
5277 pi2a->fPortType = pi2w->fPortType;
5278 pi2a->Reserved = 0; /* documented: "must be zero" */
5279
5280 }
5281 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5282 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5283 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5284 }
5285 }
5286
5287 cleanup:
5288 if (pcbNeeded) *pcbNeeded = needed;
5289 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5290
5291 HeapFree(GetProcessHeap(), 0, nameW);
5292 HeapFree(GetProcessHeap(), 0, bufferW);
5293
5294 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5295 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5296
5297 return (res);
5298
5299 }
5300
5301 /******************************************************************************
5302 * EnumPortsW (WINSPOOL.@)
5303 *
5304 * Enumerate available Ports
5305 *
5306 * PARAMS
5307 * pName [I] Servername or NULL (local Computer)
5308 * Level [I] Structure-Level (1 or 2)
5309 * pPorts [O] PTR to Buffer that receives the Result
5310 * cbBuf [I] Size of Buffer at pPorts
5311 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5312 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5313 *
5314 * RETURNS
5315 * Success: TRUE
5316 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5317 *
5318 */
5319 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5320 {
5321
5322 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5323 cbBuf, pcbNeeded, pcReturned);
5324
5325 if ((backend == NULL) && !load_backend()) return FALSE;
5326
5327 /* Level is not checked in win9x */
5328 if (!Level || (Level > 2)) {
5329 WARN("level (%d) is ignored in win9x\n", Level);
5330 SetLastError(ERROR_INVALID_LEVEL);
5331 return FALSE;
5332 }
5333 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5334 SetLastError(RPC_X_NULL_REF_POINTER);
5335 return FALSE;
5336 }
5337
5338 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5339 }
5340
5341 /******************************************************************************
5342 * GetDefaultPrinterW (WINSPOOL.@)
5343 *
5344 * FIXME
5345 * This function must read the value from data 'device' of key
5346 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5347 */
5348 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5349 {
5350 BOOL retval = TRUE;
5351 DWORD insize, len;
5352 WCHAR *buffer, *ptr;
5353
5354 if (!namesize)
5355 {
5356 SetLastError(ERROR_INVALID_PARAMETER);
5357 return FALSE;
5358 }
5359
5360 /* make the buffer big enough for the stuff from the profile/registry,
5361 * the content must fit into the local buffer to compute the correct
5362 * size even if the extern buffer is too small or not given.
5363 * (20 for ,driver,port) */
5364 insize = *namesize;
5365 len = max(100, (insize + 20));
5366 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5367
5368 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5369 {
5370 SetLastError (ERROR_FILE_NOT_FOUND);
5371 retval = FALSE;
5372 goto end;
5373 }
5374 TRACE("%s\n", debugstr_w(buffer));
5375
5376 if ((ptr = strchrW(buffer, ',')) == NULL)
5377 {
5378 SetLastError(ERROR_INVALID_NAME);
5379 retval = FALSE;
5380 goto end;
5381 }
5382
5383 *ptr = 0;
5384 *namesize = strlenW(buffer) + 1;
5385 if(!name || (*namesize > insize))
5386 {
5387 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5388 retval = FALSE;
5389 goto end;
5390 }
5391 strcpyW(name, buffer);
5392
5393 end:
5394 HeapFree( GetProcessHeap(), 0, buffer);
5395 return retval;
5396 }
5397
5398
5399 /******************************************************************************
5400 * GetDefaultPrinterA (WINSPOOL.@)
5401 */
5402 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5403 {
5404 BOOL retval = TRUE;
5405 DWORD insize = 0;
5406 WCHAR *bufferW = NULL;
5407
5408 if (!namesize)
5409 {
5410 SetLastError(ERROR_INVALID_PARAMETER);
5411 return FALSE;
5412 }
5413
5414 if(name && *namesize) {
5415 insize = *namesize;
5416 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5417 }
5418
5419 if(!GetDefaultPrinterW( bufferW, namesize)) {
5420 retval = FALSE;
5421 goto end;
5422 }
5423
5424 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5425 NULL, NULL);
5426 if (!*namesize)
5427 {
5428 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5429 retval = FALSE;
5430 }
5431 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5432
5433 end:
5434 HeapFree( GetProcessHeap(), 0, bufferW);
5435 return retval;
5436 }
5437
5438
5439 /******************************************************************************
5440 * SetDefaultPrinterW (WINSPOOL.204)
5441 *
5442 * Set the Name of the Default Printer
5443 *
5444 * PARAMS
5445 * pszPrinter [I] Name of the Printer or NULL
5446 *
5447 * RETURNS
5448 * Success: True
5449 * Failure: FALSE
5450 *
5451 * NOTES
5452 * When the Parameter is NULL or points to an Empty String and
5453 * a Default Printer was already present, then this Function changes nothing.
5454 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5455 * the First enumerated local Printer is used.
5456 *
5457 */
5458 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5459 {
5460 WCHAR default_printer[MAX_PATH];
5461 LPWSTR buffer = NULL;
5462 HKEY hreg;
5463 DWORD size;
5464 DWORD namelen;
5465 LONG lres;
5466
5467 TRACE("(%s)\n", debugstr_w(pszPrinter));
5468 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5469
5470 default_printer[0] = '\0';
5471 size = sizeof(default_printer)/sizeof(WCHAR);
5472
5473 /* if we have a default Printer, do nothing. */
5474 if (GetDefaultPrinterW(default_printer, &size))
5475 return TRUE;
5476
5477 pszPrinter = NULL;
5478 /* we have no default Printer: search local Printers and use the first */
5479 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5480
5481 default_printer[0] = '\0';
5482 size = sizeof(default_printer)/sizeof(WCHAR);
5483 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5484
5485 pszPrinter = default_printer;
5486 TRACE("using %s\n", debugstr_w(pszPrinter));
5487 }
5488 RegCloseKey(hreg);
5489 }
5490
5491 if (pszPrinter == NULL) {
5492 TRACE("no local printer found\n");
5493 SetLastError(ERROR_FILE_NOT_FOUND);
5494 return FALSE;
5495 }
5496 }
5497
5498 /* "pszPrinter" is never empty or NULL here. */
5499 namelen = lstrlenW(pszPrinter);
5500 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5501 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5502 if (!buffer ||
5503 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5504 HeapFree(GetProcessHeap(), 0, buffer);
5505 SetLastError(ERROR_FILE_NOT_FOUND);
5506 return FALSE;
5507 }
5508
5509 /* read the devices entry for the printer (driver,port) to build the string for the
5510 default device entry (printer,driver,port) */
5511 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5512 buffer[namelen] = ',';
5513 namelen++; /* move index to the start of the driver */
5514
5515 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5516 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5517 if (!lres) {
5518 TRACE("set device to %s\n", debugstr_w(buffer));
5519
5520 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
5521 TRACE("failed to set the device entry: %d\n", GetLastError());
5522 lres = ERROR_INVALID_PRINTER_NAME;
5523 }
5524
5525 /* remove the next section, when INIFileMapping is implemented */
5526 {
5527 HKEY hdev;
5528 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
5529 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
5530 RegCloseKey(hdev);
5531 }
5532 }
5533 }
5534 else
5535 {
5536 if (lres != ERROR_FILE_NOT_FOUND)
5537 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
5538
5539 SetLastError(ERROR_INVALID_PRINTER_NAME);
5540 }
5541
5542 RegCloseKey(hreg);
5543 HeapFree(GetProcessHeap(), 0, buffer);
5544 return (lres == ERROR_SUCCESS);
5545 }
5546
5547 /******************************************************************************
5548 * SetDefaultPrinterA (WINSPOOL.202)
5549 *
5550 * See SetDefaultPrinterW.
5551 *
5552 */
5553 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5554 {
5555 LPWSTR bufferW = NULL;
5556 BOOL res;
5557
5558 TRACE("(%s)\n", debugstr_a(pszPrinter));
5559 if(pszPrinter) {
5560 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
5561 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5562 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
5563 }
5564 res = SetDefaultPrinterW(bufferW);
5565 HeapFree(GetProcessHeap(), 0, bufferW);
5566 return res;
5567 }
5568
5569 /******************************************************************************
5570 * SetPrinterDataExA (WINSPOOL.@)
5571 */
5572 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5573 LPCSTR pValueName, DWORD Type,
5574 LPBYTE pData, DWORD cbData)
5575 {
5576 HKEY hkeyPrinter, hkeySubkey;
5577 DWORD ret;
5578
5579 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5580 debugstr_a(pValueName), Type, pData, cbData);
5581
5582 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5583 != ERROR_SUCCESS)
5584 return ret;
5585
5586 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5587 != ERROR_SUCCESS) {
5588 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5589 RegCloseKey(hkeyPrinter);
5590 return ret;
5591 }
5592 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5593 RegCloseKey(hkeySubkey);
5594 RegCloseKey(hkeyPrinter);
5595 return ret;
5596 }
5597
5598 /******************************************************************************
5599 * SetPrinterDataExW (WINSPOOL.@)
5600 */
5601 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5602 LPCWSTR pValueName, DWORD Type,
5603 LPBYTE pData, DWORD cbData)
5604 {
5605 HKEY hkeyPrinter, hkeySubkey;
5606 DWORD ret;
5607
5608 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5609 debugstr_w(pValueName), Type, pData, cbData);
5610
5611 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5612 != ERROR_SUCCESS)
5613 return ret;
5614
5615 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5616 != ERROR_SUCCESS) {
5617 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5618 RegCloseKey(hkeyPrinter);
5619 return ret;
5620 }
5621 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5622 RegCloseKey(hkeySubkey);
5623 RegCloseKey(hkeyPrinter);
5624 return ret;
5625 }
5626
5627 /******************************************************************************
5628 * SetPrinterDataA (WINSPOOL.@)
5629 */
5630 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5631 LPBYTE pData, DWORD cbData)
5632 {
5633 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5634 pData, cbData);
5635 }
5636
5637 /******************************************************************************
5638 * SetPrinterDataW (WINSPOOL.@)
5639 */
5640 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5641 LPBYTE pData, DWORD cbData)
5642 {
5643 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5644 pData, cbData);
5645 }
5646
5647 /******************************************************************************
5648 * GetPrinterDataExA (WINSPOOL.@)
5649 */
5650 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5651 LPCSTR pValueName, LPDWORD pType,
5652 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5653 {
5654 opened_printer_t *printer;
5655 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5656 DWORD ret;
5657
5658 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
5659 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
5660
5661 printer = get_opened_printer(hPrinter);
5662 if(!printer) return ERROR_INVALID_HANDLE;
5663
5664 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5665 if (ret) return ret;
5666
5667 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5668
5669 if (printer->name) {
5670
5671 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5672 if (ret) {
5673 RegCloseKey(hkeyPrinters);
5674 return ret;
5675 }
5676 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5677 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
5678 RegCloseKey(hkeyPrinter);
5679 RegCloseKey(hkeyPrinters);
5680 return ret;
5681 }
5682 }
5683 *pcbNeeded = nSize;
5684 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5685 0, pType, pData, pcbNeeded);
5686
5687 if (!ret && !pData) ret = ERROR_MORE_DATA;
5688
5689 RegCloseKey(hkeySubkey);
5690 RegCloseKey(hkeyPrinter);
5691 RegCloseKey(hkeyPrinters);
5692
5693 TRACE("--> %d\n", ret);
5694 return ret;
5695 }
5696
5697 /******************************************************************************
5698 * GetPrinterDataExW (WINSPOOL.@)
5699 */
5700 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5701 LPCWSTR pValueName, LPDWORD pType,
5702 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5703 {
5704 opened_printer_t *printer;
5705 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5706 DWORD ret;
5707
5708 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
5709 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
5710
5711 printer = get_opened_printer(hPrinter);
5712 if(!printer) return ERROR_INVALID_HANDLE;
5713
5714 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5715 if (ret) return ret;
5716
5717 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5718
5719 if (printer->name) {
5720
5721 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5722 if (ret) {
5723 RegCloseKey(hkeyPrinters);
5724 return ret;
5725 }
5726 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5727 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
5728 RegCloseKey(hkeyPrinter);
5729 RegCloseKey(hkeyPrinters);
5730 return ret;
5731 }
5732 }
5733 *pcbNeeded = nSize;
5734 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5735 0, pType, pData, pcbNeeded);
5736
5737 if (!ret && !pData) ret = ERROR_MORE_DATA;
5738
5739 RegCloseKey(hkeySubkey);
5740 RegCloseKey(hkeyPrinter);
5741 RegCloseKey(hkeyPrinters);
5742
5743 TRACE("--> %d\n", ret);
5744 return ret;
5745 }
5746
5747 /******************************************************************************
5748 * GetPrinterDataA (WINSPOOL.@)
5749 */
5750 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5751 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5752 {
5753 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5754 pData, nSize, pcbNeeded);
5755 }
5756
5757 /******************************************************************************
5758 * GetPrinterDataW (WINSPOOL.@)
5759 */
5760 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5761 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5762 {
5763 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5764 pData, nSize, pcbNeeded);
5765 }
5766
5767 /*******************************************************************************
5768 * EnumPrinterDataExW [WINSPOOL.@]
5769 */
5770 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5771 LPBYTE pEnumValues, DWORD cbEnumValues,
5772 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5773 {
5774 HKEY hkPrinter, hkSubKey;
5775 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5776 cbValueNameLen, cbMaxValueLen, cbValueLen,
5777 cbBufSize, dwType;
5778 LPWSTR lpValueName;
5779 HANDLE hHeap;
5780 PBYTE lpValue;
5781 PPRINTER_ENUM_VALUESW ppev;
5782
5783 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5784
5785 if (pKeyName == NULL || *pKeyName == 0)
5786 return ERROR_INVALID_PARAMETER;
5787
5788 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5789 if (ret != ERROR_SUCCESS)
5790 {
5791 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5792 hPrinter, ret);
5793 return ret;
5794 }
5795
5796 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5797 if (ret != ERROR_SUCCESS)
5798 {
5799 r = RegCloseKey (hkPrinter);
5800 if (r != ERROR_SUCCESS)
5801 WARN ("RegCloseKey returned %i\n", r);
5802 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5803 debugstr_w (pKeyName), ret);
5804 return ret;
5805 }
5806
5807 ret = RegCloseKey (hkPrinter);
5808 if (ret != ERROR_SUCCESS)
5809 {
5810 ERR ("RegCloseKey returned %i\n", ret);
5811 r = RegCloseKey (hkSubKey);
5812 if (r != ERROR_SUCCESS)
5813 WARN ("RegCloseKey returned %i\n", r);
5814 return ret;
5815 }
5816
5817 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5818 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5819 if (ret != ERROR_SUCCESS)
5820 {
5821 r = RegCloseKey (hkSubKey);
5822 if (r != ERROR_SUCCESS)
5823 WARN ("RegCloseKey returned %i\n", r);
5824 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5825 return ret;
5826 }
5827
5828 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5829 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5830
5831 if (cValues == 0) /* empty key */
5832 {
5833 r = RegCloseKey (hkSubKey);
5834 if (r != ERROR_SUCCESS)
5835 WARN ("RegCloseKey returned %i\n", r);
5836 *pcbEnumValues = *pnEnumValues = 0;
5837 return ERROR_SUCCESS;
5838 }
5839
5840 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5841
5842 hHeap = GetProcessHeap ();
5843 if (hHeap == NULL)
5844 {
5845 ERR ("GetProcessHeap failed\n");
5846 r = RegCloseKey (hkSubKey);
5847 if (r != ERROR_SUCCESS)
5848 WARN ("RegCloseKey returned %i\n", r);
5849 return ERROR_OUTOFMEMORY;
5850 }
5851
5852 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5853 if (lpValueName == NULL)
5854 {
5855 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5856 r = RegCloseKey (hkSubKey);
5857 if (r != ERROR_SUCCESS)
5858 WARN ("RegCloseKey returned %i\n", r);
5859 return ERROR_OUTOFMEMORY;
5860 }
5861
5862 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5863 if (lpValue == NULL)
5864 {
5865 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5866 if (HeapFree (hHeap, 0, lpValueName) == 0)
5867 WARN ("HeapFree failed with code %i\n", GetLastError ());
5868 r = RegCloseKey (hkSubKey);
5869 if (r != ERROR_SUCCESS)
5870 WARN ("RegCloseKey returned %i\n", r);
5871 return ERROR_OUTOFMEMORY;
5872 }
5873
5874 TRACE ("pass 1: calculating buffer required for all names and values\n");
5875
5876 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5877
5878 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5879
5880 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5881 {
5882 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5883 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5884 NULL, NULL, lpValue, &cbValueLen);
5885 if (ret != ERROR_SUCCESS)
5886 {
5887 if (HeapFree (hHeap, 0, lpValue) == 0)
5888 WARN ("HeapFree failed with code %i\n", GetLastError ());
5889 if (HeapFree (hHeap, 0, lpValueName) == 0)
5890 WARN ("HeapFree failed with code %i\n", GetLastError ());
5891 r = RegCloseKey (hkSubKey);
5892 if (r != ERROR_SUCCESS)
5893 WARN ("RegCloseKey returned %i\n", r);
5894 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5895 return ret;
5896 }
5897
5898 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5899 debugstr_w (lpValueName), dwIndex,
5900 cbValueNameLen + 1, cbValueLen);
5901
5902 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5903 cbBufSize += cbValueLen;
5904 }
5905
5906 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5907
5908 *pcbEnumValues = cbBufSize;
5909 *pnEnumValues = cValues;
5910
5911 if (cbEnumValues < cbBufSize) /* buffer too small */
5912 {
5913 if (HeapFree (hHeap, 0, lpValue) == 0)
5914 WARN ("HeapFree failed with code %i\n", GetLastError ());
5915 if (HeapFree (hHeap, 0, lpValueName) == 0)
5916 WARN ("HeapFree failed with code %i\n", GetLastError ());
5917 r = RegCloseKey (hkSubKey);
5918 if (r != ERROR_SUCCESS)
5919 WARN ("RegCloseKey returned %i\n", r);
5920 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5921 return ERROR_MORE_DATA;
5922 }
5923
5924 TRACE ("pass 2: copying all names and values to buffer\n");
5925
5926 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5927 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5928
5929 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5930 {
5931 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5932 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5933 NULL, &dwType, lpValue, &cbValueLen);
5934 if (ret != ERROR_SUCCESS)
5935 {
5936 if (HeapFree (hHeap, 0, lpValue) == 0)
5937 WARN ("HeapFree failed with code %i\n", GetLastError ());
5938 if (HeapFree (hHeap, 0, lpValueName) == 0)
5939 WARN ("HeapFree failed with code %i\n", GetLastError ());
5940 r = RegCloseKey (hkSubKey);
5941 if (r != ERROR_SUCCESS)
5942 WARN ("RegCloseKey returned %i\n", r);
5943 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5944 return ret;
5945 }
5946
5947 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5948 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5949 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5950 pEnumValues += cbValueNameLen;
5951
5952 /* return # of *bytes* (including trailing \0), not # of chars */
5953 ppev[dwIndex].cbValueName = cbValueNameLen;
5954
5955 ppev[dwIndex].dwType = dwType;
5956
5957 memcpy (pEnumValues, lpValue, cbValueLen);
5958 ppev[dwIndex].pData = pEnumValues;
5959 pEnumValues += cbValueLen;
5960
5961 ppev[dwIndex].cbData = cbValueLen;
5962
5963 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5964 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5965 }
5966
5967 if (HeapFree (hHeap, 0, lpValue) == 0)
5968 {
5969 ret = GetLastError ();
5970 ERR ("HeapFree failed with code %i\n", ret);
5971 if (HeapFree (hHeap, 0, lpValueName) == 0)
5972 WARN ("HeapFree failed with code %i\n", GetLastError ());
5973 r = RegCloseKey (hkSubKey);
5974 if (r != ERROR_SUCCESS)
5975 WARN ("RegCloseKey returned %i\n", r);
5976 return ret;
5977 }
5978
5979 if (HeapFree (hHeap, 0, lpValueName) == 0)
5980 {
5981 ret = GetLastError ();
5982 ERR ("HeapFree failed with code %i\n", ret);
5983 r = RegCloseKey (hkSubKey);
5984 if (r != ERROR_SUCCESS)
5985 WARN ("RegCloseKey returned %i\n", r);
5986 return ret;
5987 }
5988
5989 ret = RegCloseKey (hkSubKey);
5990 if (ret != ERROR_SUCCESS)
5991 {
5992 ERR ("RegCloseKey returned %i\n", ret);
5993 return ret;
5994 }
5995
5996 return ERROR_SUCCESS;
5997 }
5998
5999 /*******************************************************************************
6000 * EnumPrinterDataExA [WINSPOOL.@]
6001 *
6002 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6003 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6004 * what Windows 2000 SP1 does.
6005 *
6006 */
6007 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6008 LPBYTE pEnumValues, DWORD cbEnumValues,
6009 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6010 {
6011 INT len;
6012 LPWSTR pKeyNameW;
6013 DWORD ret, dwIndex, dwBufSize;
6014 HANDLE hHeap;
6015 LPSTR pBuffer;
6016
6017 TRACE ("%p %s\n", hPrinter, pKeyName);
6018
6019 if (pKeyName == NULL || *pKeyName == 0)
6020 return ERROR_INVALID_PARAMETER;
6021
6022 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6023 if (len == 0)
6024 {
6025 ret = GetLastError ();
6026 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6027 return ret;
6028 }
6029
6030 hHeap = GetProcessHeap ();
6031 if (hHeap == NULL)
6032 {
6033 ERR ("GetProcessHeap failed\n");
6034 return ERROR_OUTOFMEMORY;
6035 }
6036
6037 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6038 if (pKeyNameW == NULL)
6039 {
6040 ERR ("Failed to allocate %i bytes from process heap\n",
6041 (LONG)(len * sizeof (WCHAR)));
6042 return ERROR_OUTOFMEMORY;
6043 }
6044
6045 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6046 {
6047 ret = GetLastError ();
6048 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6049 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6050 WARN ("HeapFree failed with code %i\n", GetLastError ());
6051 return ret;
6052 }
6053
6054 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6055 pcbEnumValues, pnEnumValues);
6056 if (ret != ERROR_SUCCESS)
6057 {
6058 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6059 WARN ("HeapFree failed with code %i\n", GetLastError ());
6060 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6061 return ret;
6062 }
6063
6064 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6065 {
6066 ret = GetLastError ();
6067 ERR ("HeapFree failed with code %i\n", ret);
6068 return ret;
6069 }
6070
6071 if (*pnEnumValues == 0) /* empty key */
6072 return ERROR_SUCCESS;
6073
6074 dwBufSize = 0;
6075 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6076 {
6077 PPRINTER_ENUM_VALUESW ppev =
6078 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6079
6080 if (dwBufSize < ppev->cbValueName)
6081 dwBufSize = ppev->cbValueName;
6082
6083 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6084 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6085 dwBufSize = ppev->cbData;
6086 }
6087
6088 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6089
6090 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6091 if (pBuffer == NULL)
6092 {
6093 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6094 return ERROR_OUTOFMEMORY;
6095 }
6096
6097 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6098 {
6099 PPRINTER_ENUM_VALUESW ppev =
6100 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6101
6102 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6103 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6104 NULL);
6105 if (len == 0)
6106 {
6107 ret = GetLastError ();
6108 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6109 if (HeapFree (hHeap, 0, pBuffer) == 0)
6110 WARN ("HeapFree failed with code %i\n", GetLastError ());
6111 return ret;
6112 }
6113
6114 memcpy (ppev->pValueName, pBuffer, len);
6115
6116 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6117
6118 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6119 ppev->dwType != REG_MULTI_SZ)
6120 continue;
6121
6122 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6123 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6124 if (len == 0)
6125 {
6126 ret = GetLastError ();
6127 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6128 if (HeapFree (hHeap, 0, pBuffer) == 0)
6129 WARN ("HeapFree failed with code %i\n", GetLastError ());
6130 return ret;
6131 }
6132
6133 memcpy (ppev->pData, pBuffer, len);
6134
6135 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6136 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6137 }
6138
6139 if (HeapFree (hHeap, 0, pBuffer) == 0)
6140 {
6141 ret = GetLastError ();
6142 ERR ("HeapFree failed with code %i\n", ret);
6143 return ret;
6144 }
6145
6146 return ERROR_SUCCESS;
6147 }
6148
6149 /******************************************************************************
6150 * AbortPrinter (WINSPOOL.@)
6151 */
6152 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6153 {
6154 FIXME("(%p), stub!\n", hPrinter);
6155 return TRUE;
6156 }
6157
6158 /******************************************************************************
6159 * AddPortA (WINSPOOL.@)
6160 *
6161 * See AddPortW.
6162 *
6163 */
6164 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6165 {
6166 LPWSTR nameW = NULL;
6167 LPWSTR monitorW = NULL;
6168 DWORD len;
6169 BOOL res;
6170
6171 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6172
6173 if (pName) {
6174 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6175 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6176 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6177 }
6178
6179 if (pMonitorName) {
6180 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6181 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6182 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6183 }
6184 res = AddPortW(nameW, hWnd, monitorW);
6185 HeapFree(GetProcessHeap(), 0, nameW);
6186 HeapFree(GetProcessHeap(), 0, monitorW);
6187 return res;
6188 }
6189
6190 /******************************************************************************
6191 * AddPortW (WINSPOOL.@)
6192 *
6193 * Add a Port for a specific Monitor
6194 *
6195 * PARAMS
6196 * pName [I] Servername or NULL (local Computer)
6197 * hWnd [I] Handle to parent Window for the Dialog-Box
6198 * pMonitorName [I] Name of the Monitor that manage the Port
6199 *
6200 * RETURNS
6201 * Success: TRUE
6202 * Failure: FALSE
6203 *
6204 */
6205 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6206 {
6207 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6208
6209 if ((backend == NULL) && !load_backend()) return FALSE;
6210
6211 if (!pMonitorName) {
6212 SetLastError(RPC_X_NULL_REF_POINTER);
6213 return FALSE;
6214 }
6215
6216 return backend->fpAddPort(pName, hWnd, pMonitorName);
6217 }
6218
6219 /******************************************************************************
6220 * AddPortExA (WINSPOOL.@)
6221 *
6222 * See AddPortExW.
6223 *
6224 */
6225 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6226 {
6227 PORT_INFO_2W pi2W;
6228 PORT_INFO_2A * pi2A;
6229 LPWSTR nameW = NULL;
6230 LPWSTR monitorW = NULL;
6231 DWORD len;
6232 BOOL res;
6233
6234 pi2A = (PORT_INFO_2A *) pBuffer;
6235
6236 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6237 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6238
6239 if ((level < 1) || (level > 2)) {
6240 SetLastError(ERROR_INVALID_LEVEL);
6241 return FALSE;
6242 }
6243
6244 if (!pi2A) {
6245 SetLastError(ERROR_INVALID_PARAMETER);
6246 return FALSE;
6247 }
6248
6249 if (pName) {
6250 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6251 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6252 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6253 }
6254
6255 if (pMonitorName) {
6256 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6257 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6258 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6259 }
6260
6261 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6262
6263 if (pi2A->pPortName) {
6264 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6265 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6266 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6267 }
6268
6269 if (level > 1) {
6270 if (pi2A->pMonitorName) {
6271 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6272 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6273 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6274 }
6275
6276 if (pi2A->pDescription) {
6277 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6278 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6279 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6280 }
6281 pi2W.fPortType = pi2A->fPortType;
6282 pi2W.Reserved = pi2A->Reserved;
6283 }
6284
6285 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6286
6287 HeapFree(GetProcessHeap(), 0, nameW);
6288 HeapFree(GetProcessHeap(), 0, monitorW);
6289 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6290 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6291 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6292 return res;
6293
6294 }
6295
6296 /******************************************************************************
6297 * AddPortExW (WINSPOOL.@)
6298 *
6299 * Add a Port for a specific Monitor, without presenting a user interface
6300 *
6301 * PARAMS
6302 * pName [I] Servername or NULL (local Computer)
6303 * level [I] Structure-Level (1 or 2) for pBuffer
6304 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6305 * pMonitorName [I] Name of the Monitor that manage the Port
6306 *
6307 * RETURNS
6308 * Success: TRUE
6309 * Failure: FALSE
6310 *
6311 */
6312 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6313 {
6314 PORT_INFO_2W * pi2;
6315
6316 pi2 = (PORT_INFO_2W *) pBuffer;
6317
6318 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6319 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6320 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6321 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6322
6323 if ((backend == NULL) && !load_backend()) return FALSE;
6324
6325 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6326 SetLastError(ERROR_INVALID_PARAMETER);
6327 return FALSE;
6328 }
6329
6330 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6331 }
6332
6333 /******************************************************************************
6334 * AddPrinterConnectionA (WINSPOOL.@)
6335 */
6336 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6337 {
6338 FIXME("%s\n", debugstr_a(pName));
6339 return FALSE;
6340 }
6341
6342 /******************************************************************************
6343 * AddPrinterConnectionW (WINSPOOL.@)
6344 */
6345 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6346 {
6347 FIXME("%s\n", debugstr_w(pName));
6348 return FALSE;
6349 }
6350
6351 /******************************************************************************
6352 * AddPrinterDriverExW (WINSPOOL.@)
6353 *
6354 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6355 *
6356 * PARAMS
6357 * pName [I] Servername or NULL (local Computer)
6358 * level [I] Level for the supplied DRIVER_INFO_*W struct
6359 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6360 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6361 *
6362 * RESULTS
6363 * Success: TRUE
6364 * Failure: FALSE
6365 *
6366 */
6367 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6368 {
6369 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6370
6371 if ((backend == NULL) && !load_backend()) return FALSE;
6372
6373 if (level < 2 || level == 5 || level == 7 || level > 8) {
6374 SetLastError(ERROR_INVALID_LEVEL);
6375 return FALSE;
6376 }
6377
6378 if (!pDriverInfo) {
6379 SetLastError(ERROR_INVALID_PARAMETER);
6380 return FALSE;
6381 }
6382
6383 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6384 }
6385
6386 /******************************************************************************
6387 * AddPrinterDriverExA (WINSPOOL.@)
6388 *
6389 * See AddPrinterDriverExW.
6390 *
6391 */
6392 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6393 {
6394 DRIVER_INFO_8A *diA;
6395 DRIVER_INFO_8W diW;
6396 LPWSTR nameW = NULL;
6397 DWORD lenA;
6398 DWORD len;
6399 DWORD res = FALSE;
6400
6401 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6402
6403 diA = (DRIVER_INFO_8A *) pDriverInfo;
6404 ZeroMemory(&diW, sizeof(diW));
6405
6406 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6407 SetLastError(ERROR_INVALID_LEVEL);
6408 return FALSE;
6409 }
6410
6411 if (diA == NULL) {
6412 SetLastError(ERROR_INVALID_PARAMETER);
6413 return FALSE;
6414 }
6415
6416 /* convert servername to unicode */
6417 if (pName) {
6418 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6419 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6420 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6421 }
6422
6423 /* common fields */
6424 diW.cVersion = diA->cVersion;
6425
6426 if (diA->pName) {
6427 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6428 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6429 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6430 }
6431
6432 if (diA->pEnvironment) {
6433 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6434 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6435 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6436 }
6437
6438 if (diA->pDriverPath) {
6439 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6440 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6441 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6442 }
6443
6444 if (diA->pDataFile) {
6445 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6446 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6447 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6448 }
6449
6450 if (diA->pConfigFile) {
6451 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6452 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6453 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6454 }
6455
6456 if ((Level > 2) && diA->pDependentFiles) {
6457 lenA = multi_sz_lenA(diA->pDependentFiles);
6458 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6459 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6460 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6461 }
6462
6463 if ((Level > 2) && diA->pMonitorName) {
6464 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6465 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6466 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6467 }
6468
6469 if ((Level > 3) && diA->pDefaultDataType) {
6470 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6471 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6472 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6473 }
6474
6475 if ((Level > 3) && diA->pszzPreviousNames) {
6476 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6477 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6478 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6479 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6480 }
6481
6482 if ((Level > 5) && diA->pszMfgName) {
6483 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6484 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6485 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6486 }
6487
6488 if ((Level > 5) && diA->pszOEMUrl) {
6489 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6490 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6491 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6492 }
6493
6494 if ((Level > 5) && diA->pszHardwareID) {
6495 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6496 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6497 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6498 }
6499
6500 if ((Level > 5) && diA->pszProvider) {
6501 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6502 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6503 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6504 }
6505
6506 if (Level > 7) {
6507 FIXME("level %u is incomplete\n", Level);
6508 }
6509
6510 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6511 TRACE("got %u with %u\n", res, GetLastError());
6512 HeapFree(GetProcessHeap(), 0, nameW);
6513 HeapFree(GetProcessHeap(), 0, diW.pName);
6514 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6515 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6516 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6517 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6518 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6519 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6520 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6521 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6522 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6523 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6524 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6525 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6526
6527 TRACE("=> %u with %u\n", res, GetLastError());
6528 return res;
6529 }
6530
6531 /******************************************************************************
6532 * ConfigurePortA (WINSPOOL.@)
6533 *
6534 * See ConfigurePortW.
6535 *
6536 */
6537 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6538 {
6539 LPWSTR nameW = NULL;
6540 LPWSTR portW = NULL;
6541 INT len;
6542 DWORD res;
6543
6544 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6545
6546 /* convert servername to unicode */
6547 if (pName) {
6548 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6549 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6550 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6551 }
6552
6553 /* convert portname to unicode */
6554 if (pPortName) {
6555 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6556 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6557 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6558 }
6559
6560 res = ConfigurePortW(nameW, hWnd, portW);
6561 HeapFree(GetProcessHeap(), 0, nameW);
6562 HeapFree(GetProcessHeap(), 0, portW);
6563 return res;
6564 }
6565
6566 /******************************************************************************
6567 * ConfigurePortW (WINSPOOL.@)
6568 *
6569 * Display the Configuration-Dialog for a specific Port
6570 *
6571 * PARAMS
6572 * pName [I] Servername or NULL (local Computer)
6573 * hWnd [I] Handle to parent Window for the Dialog-Box
6574 * pPortName [I] Name of the Port, that should be configured
6575 *
6576 * RETURNS
6577 * Success: TRUE
6578 * Failure: FALSE
6579 *
6580 */
6581 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6582 {
6583
6584 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6585
6586 if ((backend == NULL) && !load_backend()) return FALSE;
6587
6588 if (!pPortName) {
6589 SetLastError(RPC_X_NULL_REF_POINTER);
6590 return FALSE;
6591 }
6592
6593 return backend->fpConfigurePort(pName, hWnd, pPortName);
6594 }
6595
6596 /******************************************************************************
6597 * ConnectToPrinterDlg (WINSPOOL.@)
6598 */
6599 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6600 {
6601 FIXME("%p %x\n", hWnd, Flags);
6602 return NULL;
6603 }
6604
6605 /******************************************************************************
6606 * DeletePrinterConnectionA (WINSPOOL.@)
6607 */
6608 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6609 {
6610 FIXME("%s\n", debugstr_a(pName));
6611 return TRUE;
6612 }
6613
6614 /******************************************************************************
6615 * DeletePrinterConnectionW (WINSPOOL.@)
6616 */
6617 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6618 {
6619 FIXME("%s\n", debugstr_w(pName));
6620 return TRUE;
6621 }
6622
6623 /******************************************************************************
6624 * DeletePrinterDriverExW (WINSPOOL.@)
6625 */
6626 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6627 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6628 {
6629 HKEY hkey_drivers;
6630 BOOL ret = FALSE;
6631
6632 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6633 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6634
6635 if(pName && pName[0])
6636 {
6637 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6638 SetLastError(ERROR_INVALID_PARAMETER);
6639 return FALSE;
6640 }
6641
6642 if(dwDeleteFlag)
6643 {
6644 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6645 SetLastError(ERROR_INVALID_PARAMETER);
6646 return FALSE;
6647 }
6648
6649 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6650
6651 if(!hkey_drivers)
6652 {
6653 ERR("Can't open drivers key\n");
6654 return FALSE;
6655 }
6656
6657 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6658 ret = TRUE;
6659
6660 RegCloseKey(hkey_drivers);
6661
6662 return ret;
6663 }
6664
6665 /******************************************************************************
6666 * DeletePrinterDriverExA (WINSPOOL.@)
6667 */
6668 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6669 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6670 {
6671 UNICODE_STRING NameW, EnvW, DriverW;
6672 BOOL ret;
6673
6674 asciitounicode(&NameW, pName);
6675 asciitounicode(&EnvW, pEnvironment);
6676 asciitounicode(&DriverW, pDriverName);
6677
6678 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6679
6680 RtlFreeUnicodeString(&DriverW);
6681 RtlFreeUnicodeString(&EnvW);
6682 RtlFreeUnicodeString(&NameW);
6683
6684 return ret;
6685 }
6686
6687 /******************************************************************************
6688 * DeletePrinterDataExW (WINSPOOL.@)
6689 */
6690 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6691 LPCWSTR pValueName)
6692 {
6693 FIXME("%p %s %s\n", hPrinter,
6694 debugstr_w(pKeyName), debugstr_w(pValueName));
6695 return ERROR_INVALID_PARAMETER;
6696 }
6697
6698 /******************************************************************************
6699 * DeletePrinterDataExA (WINSPOOL.@)
6700 */
6701 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6702 LPCSTR pValueName)
6703 {
6704 FIXME("%p %s %s\n", hPrinter,
6705 debugstr_a(pKeyName), debugstr_a(pValueName));
6706 return ERROR_INVALID_PARAMETER;
6707 }
6708
6709 /******************************************************************************
6710 * DeletePrintProcessorA (WINSPOOL.@)
6711 */
6712 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6713 {
6714 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6715 debugstr_a(pPrintProcessorName));
6716 return TRUE;
6717 }
6718
6719 /******************************************************************************
6720 * DeletePrintProcessorW (WINSPOOL.@)
6721 */
6722 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6723 {
6724 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6725 debugstr_w(pPrintProcessorName));
6726 return TRUE;
6727 }
6728
6729 /******************************************************************************
6730 * DeletePrintProvidorA (WINSPOOL.@)
6731 */
6732 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6733 {
6734 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6735 debugstr_a(pPrintProviderName));
6736 return TRUE;
6737 }
6738
6739 /******************************************************************************
6740 * DeletePrintProvidorW (WINSPOOL.@)
6741 */
6742 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6743 {
6744 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6745 debugstr_w(pPrintProviderName));
6746 return TRUE;
6747 }
6748
6749 /******************************************************************************
6750 * EnumFormsA (WINSPOOL.@)
6751 */
6752 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6753 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6754 {
6755 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6756 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6757 return FALSE;
6758 }
6759
6760 /******************************************************************************
6761 * EnumFormsW (WINSPOOL.@)
6762 */
6763 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6764 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6765 {
6766 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6767 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6768 return FALSE;
6769 }
6770
6771 /*****************************************************************************
6772 * EnumMonitorsA [WINSPOOL.@]
6773 *
6774 * See EnumMonitorsW.
6775 *
6776 */
6777 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6778 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6779 {
6780 BOOL res;
6781 LPBYTE bufferW = NULL;
6782 LPWSTR nameW = NULL;
6783 DWORD needed = 0;
6784 DWORD numentries = 0;
6785 INT len;
6786
6787 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6788 cbBuf, pcbNeeded, pcReturned);
6789
6790 /* convert servername to unicode */
6791 if (pName) {
6792 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6793 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6794 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6795 }
6796 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6797 needed = cbBuf * sizeof(WCHAR);
6798 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6799 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6800
6801 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6802 if (pcbNeeded) needed = *pcbNeeded;
6803 /* HeapReAlloc return NULL, when bufferW was NULL */
6804 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6805 HeapAlloc(GetProcessHeap(), 0, needed);
6806
6807 /* Try again with the large Buffer */
6808 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6809 }
6810 numentries = pcReturned ? *pcReturned : 0;
6811 needed = 0;
6812 /*
6813 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6814 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6815 */
6816 if (res) {
6817 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6818 DWORD entrysize = 0;
6819 DWORD index;
6820 LPSTR ptr;
6821 LPMONITOR_INFO_2W mi2w;
6822 LPMONITOR_INFO_2A mi2a;
6823
6824 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6825 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6826
6827 /* First pass: calculate the size for all Entries */
6828 mi2w = (LPMONITOR_INFO_2W) bufferW;
6829 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6830 index = 0;
6831 while (index < numentries) {
6832 index++;
6833 needed += entrysize; /* MONITOR_INFO_?A */
6834 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6835
6836 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6837 NULL, 0, NULL, NULL);
6838 if (Level > 1) {
6839 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6840 NULL, 0, NULL, NULL);
6841 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6842 NULL, 0, NULL, NULL);
6843 }
6844 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6845 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6846 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6847 }
6848
6849 /* check for errors and quit on failure */
6850 if (cbBuf < needed) {
6851 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6852 res = FALSE;
6853 goto emA_cleanup;
6854 }
6855 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6856 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6857 cbBuf -= len ; /* free Bytes in the user-Buffer */
6858 mi2w = (LPMONITOR_INFO_2W) bufferW;
6859 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6860 index = 0;
6861 /* Second Pass: Fill the User Buffer (if we have one) */
6862 while ((index < numentries) && pMonitors) {
6863 index++;
6864 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6865 mi2a->pName = ptr;
6866 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6867 ptr, cbBuf , NULL, NULL);
6868 ptr += len;
6869 cbBuf -= len;
6870 if (Level > 1) {
6871 mi2a->pEnvironment = ptr;
6872 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6873 ptr, cbBuf, NULL, NULL);
6874 ptr += len;
6875 cbBuf -= len;
6876
6877 mi2a->pDLLName = ptr;
6878 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6879 ptr, cbBuf, NULL, NULL);
6880 ptr += len;
6881 cbBuf -= len;
6882 }
6883 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6884 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6885 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6886 }
6887 }
6888 emA_cleanup:
6889 if (pcbNeeded) *pcbNeeded = needed;
6890 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6891
6892 HeapFree(GetProcessHeap(), 0, nameW);
6893 HeapFree(GetProcessHeap(), 0, bufferW);
6894
6895 TRACE("returning %d with %d (%d byte for %d entries)\n",
6896 (res), GetLastError(), needed, numentries);
6897
6898 return (res);
6899
6900 }
6901
6902 /*****************************************************************************
6903 * EnumMonitorsW [WINSPOOL.@]
6904 *
6905 * Enumerate available Port-Monitors
6906 *
6907 * PARAMS
6908 * pName [I] Servername or NULL (local Computer)
6909 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6910 * pMonitors [O] PTR to Buffer that receives the Result
6911 * cbBuf [I] Size of Buffer at pMonitors
6912 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6913 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6914 *
6915 * RETURNS
6916 * Success: TRUE
6917 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6918 *
6919 */
6920 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6921 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6922 {
6923
6924 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6925 cbBuf, pcbNeeded, pcReturned);
6926
6927 if ((backend == NULL) && !load_backend()) return FALSE;
6928
6929 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6930 SetLastError(RPC_X_NULL_REF_POINTER);
6931 return FALSE;
6932 }
6933
6934 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6935 }
6936
6937 /******************************************************************************
6938 * SpoolerInit (WINSPOOL.@)
6939 *
6940 * Initialize the Spooler
6941 *
6942 * RETURNS
6943 * Success: TRUE
6944 * Failure: FALSE
6945 *
6946 * NOTES
6947 * The function fails on windows, when the spooler service is not running
6948 *
6949 */
6950 BOOL WINAPI SpoolerInit(void)
6951 {
6952
6953 if ((backend == NULL) && !load_backend()) return FALSE;
6954 return TRUE;
6955 }
6956
6957 /******************************************************************************
6958 * XcvDataW (WINSPOOL.@)
6959 *
6960 * Execute commands in the Printmonitor DLL
6961 *
6962 * PARAMS
6963 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6964 * pszDataName [i] Name of the command to execute
6965 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6966 * cbInputData [i] Size in Bytes of Buffer at pInputData
6967 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6968 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6969 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6970 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6971 *
6972 * RETURNS
6973 * Success: TRUE
6974 * Failure: FALSE
6975 *
6976 * NOTES
6977 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6978 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6979 *
6980 * Minimal List of commands, that a Printmonitor DLL should support:
6981 *
6982 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6983 *| "AddPort" : Add a Port
6984 *| "DeletePort": Delete a Port
6985 *
6986 * Many Printmonitors support additional commands. Examples for localspl.dll:
6987 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6988 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6989 *
6990 */
6991 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6992 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6993 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6994 {
6995 opened_printer_t *printer;
6996
6997 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6998 pInputData, cbInputData, pOutputData,
6999 cbOutputData, pcbOutputNeeded, pdwStatus);
7000
7001 if ((backend == NULL) && !load_backend()) return FALSE;
7002
7003 printer = get_opened_printer(hXcv);
7004 if (!printer || (!printer->backend_printer)) {
7005 SetLastError(ERROR_INVALID_HANDLE);
7006 return FALSE;
7007 }
7008
7009 if (!pcbOutputNeeded) {
7010 SetLastError(ERROR_INVALID_PARAMETER);
7011 return FALSE;
7012 }
7013
7014 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7015 SetLastError(RPC_X_NULL_REF_POINTER);
7016 return FALSE;
7017 }
7018
7019 *pcbOutputNeeded = 0;
7020
7021 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
7022 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
7023
7024 }
7025
7026 /*****************************************************************************
7027 * EnumPrinterDataA [WINSPOOL.@]
7028 *
7029 */
7030 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7031 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7032 DWORD cbData, LPDWORD pcbData )
7033 {
7034 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7035 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7036 return ERROR_NO_MORE_ITEMS;
7037 }
7038
7039 /*****************************************************************************
7040 * EnumPrinterDataW [WINSPOOL.@]
7041 *
7042 */
7043 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7044 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7045 DWORD cbData, LPDWORD pcbData )
7046 {
7047 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7048 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7049 return ERROR_NO_MORE_ITEMS;
7050 }
7051
7052 /*****************************************************************************
7053 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7054 *
7055 */
7056 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7057 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7058 LPDWORD pcbNeeded, LPDWORD pcReturned)
7059 {
7060 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7061 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7062 pcbNeeded, pcReturned);
7063 return FALSE;
7064 }
7065
7066 /*****************************************************************************
7067 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7068 *
7069 */
7070 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7071 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7072 LPDWORD pcbNeeded, LPDWORD pcReturned)
7073 {
7074 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7075 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7076 pcbNeeded, pcReturned);
7077 return FALSE;
7078 }
7079
7080 /*****************************************************************************
7081 * EnumPrintProcessorsA [WINSPOOL.@]
7082 *
7083 * See EnumPrintProcessorsW.
7084 *
7085 */
7086 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7087 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7088 {
7089 BOOL res;
7090 LPBYTE bufferW = NULL;
7091 LPWSTR nameW = NULL;
7092 LPWSTR envW = NULL;
7093 DWORD needed = 0;
7094 DWORD numentries = 0;
7095 INT len;
7096
7097 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7098 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7099
7100 /* convert names to unicode */
7101 if (pName) {
7102 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7103 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7104 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7105 }
7106 if (pEnvironment) {
7107 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7108 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7109 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7110 }
7111
7112 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7113 needed = cbBuf * sizeof(WCHAR);
7114 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7115 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7116
7117 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7118 if (pcbNeeded) needed = *pcbNeeded;
7119 /* HeapReAlloc return NULL, when bufferW was NULL */
7120 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7121 HeapAlloc(GetProcessHeap(), 0, needed);
7122
7123 /* Try again with the large Buffer */
7124 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7125 }
7126 numentries = pcReturned ? *pcReturned : 0;
7127 needed = 0;
7128
7129 if (res) {
7130 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7131 DWORD index;
7132 LPSTR ptr;
7133 PPRINTPROCESSOR_INFO_1W ppiw;
7134 PPRINTPROCESSOR_INFO_1A ppia;
7135
7136 /* First pass: calculate the size for all Entries */
7137 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7138 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7139 index = 0;
7140 while (index < numentries) {
7141 index++;
7142 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7143 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7144
7145 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7146 NULL, 0, NULL, NULL);
7147
7148 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7149 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7150 }
7151
7152 /* check for errors and quit on failure */
7153 if (cbBuf < needed) {
7154 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7155 res = FALSE;
7156 goto epp_cleanup;
7157 }
7158
7159 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7160 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7161 cbBuf -= len ; /* free Bytes in the user-Buffer */
7162 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7163 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7164 index = 0;
7165 /* Second Pass: Fill the User Buffer (if we have one) */
7166 while ((index < numentries) && pPPInfo) {
7167 index++;
7168 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7169 ppia->pName = ptr;
7170 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7171 ptr, cbBuf , NULL, NULL);
7172 ptr += len;
7173 cbBuf -= len;
7174
7175 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7176 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7177
7178 }
7179 }
7180 epp_cleanup:
7181 if (pcbNeeded) *pcbNeeded = needed;
7182 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7183
7184 HeapFree(GetProcessHeap(), 0, nameW);
7185 HeapFree(GetProcessHeap(), 0, envW);
7186 HeapFree(GetProcessHeap(), 0, bufferW);
7187
7188 TRACE("returning %d with %d (%d byte for %d entries)\n",
7189 (res), GetLastError(), needed, numentries);
7190
7191 return (res);
7192 }
7193
7194 /*****************************************************************************
7195 * EnumPrintProcessorsW [WINSPOOL.@]
7196 *
7197 * Enumerate available Print Processors
7198 *
7199 * PARAMS
7200 * pName [I] Servername or NULL (local Computer)
7201 * pEnvironment [I] Printing-Environment or NULL (Default)
7202 * Level [I] Structure-Level (Only 1 is allowed)
7203 * pPPInfo [O] PTR to Buffer that receives the Result
7204 * cbBuf [I] Size of Buffer at pPPInfo
7205 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7206 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7207 *
7208 * RETURNS
7209 * Success: TRUE
7210 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7211 *
7212 */
7213 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7214 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7215 {
7216
7217 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7218 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7219
7220 if ((backend == NULL) && !load_backend()) return FALSE;
7221
7222 if (!pcbNeeded || !pcReturned) {
7223 SetLastError(RPC_X_NULL_REF_POINTER);
7224 return FALSE;
7225 }
7226
7227 if (!pPPInfo && (cbBuf > 0)) {
7228 SetLastError(ERROR_INVALID_USER_BUFFER);
7229 return FALSE;
7230 }
7231
7232 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7233 cbBuf, pcbNeeded, pcReturned);
7234 }
7235
7236 /*****************************************************************************
7237 * ExtDeviceMode [WINSPOOL.@]
7238 *
7239 */
7240 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7241 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7242 DWORD fMode)
7243 {
7244 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7245 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7246 debugstr_a(pProfile), fMode);
7247 return -1;
7248 }
7249
7250 /*****************************************************************************
7251 * FindClosePrinterChangeNotification [WINSPOOL.@]
7252 *
7253 */
7254 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7255 {
7256 FIXME("Stub: %p\n", hChange);
7257 return TRUE;
7258 }
7259
7260 /*****************************************************************************
7261 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7262 *
7263 */
7264 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7265 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7266 {
7267 FIXME("Stub: %p %x %x %p\n",
7268 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7269 return INVALID_HANDLE_VALUE;
7270 }
7271
7272 /*****************************************************************************
7273 * FindNextPrinterChangeNotification [WINSPOOL.@]
7274 *
7275 */
7276 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7277 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7278 {
7279 FIXME("Stub: %p %p %p %p\n",
7280 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7281 return FALSE;
7282 }
7283
7284 /*****************************************************************************
7285 * FreePrinterNotifyInfo [WINSPOOL.@]
7286 *
7287 */
7288 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7289 {
7290 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7291 return TRUE;
7292 }
7293
7294 /*****************************************************************************
7295 * string_to_buf
7296 *
7297 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7298 * ansi depending on the unicode parameter.
7299 */
7300 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7301 {
7302 if(!str)
7303 {
7304 *size = 0;
7305 return TRUE;
7306 }
7307
7308 if(unicode)
7309 {
7310 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7311 if(*size <= cb)
7312 {
7313 memcpy(ptr, str, *size);
7314 return TRUE;
7315 }
7316 return FALSE;
7317 }
7318 else
7319 {
7320 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7321 if(*size <= cb)
7322 {
7323 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7324 return TRUE;
7325 }
7326 return FALSE;
7327 }
7328 }
7329
7330 /*****************************************************************************
7331 * get_job_info_1
7332 */
7333 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7334 LPDWORD pcbNeeded, BOOL unicode)
7335 {
7336 DWORD size, left = cbBuf;
7337 BOOL space = (cbBuf > 0);
7338 LPBYTE ptr = buf;
7339
7340 *pcbNeeded = 0;
7341
7342 if(space)
7343 {
7344 ji1->JobId = job->job_id;
7345 }
7346
7347 string_to_buf(job->document_title, ptr, left, &size, unicode);
7348 if(space && size <= left)
7349 {
7350 ji1->pDocument = (LPWSTR)ptr;
7351 ptr += size;
7352 left -= size;
7353 }
7354 else
7355 space = FALSE;
7356 *pcbNeeded += size;
7357
7358 if (job->printer_name)
7359 {
7360 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7361 if(space && size <= left)
7362 {
7363 ji1->pPrinterName = (LPWSTR)ptr;
7364 ptr += size;
7365 left -= size;
7366 }
7367 else
7368 space = FALSE;
7369 *pcbNeeded += size;
7370 }
7371
7372 return space;
7373 }
7374
7375 /*****************************************************************************
7376 * get_job_info_2
7377 */
7378 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7379 LPDWORD pcbNeeded, BOOL unicode)
7380 {
7381 DWORD size, left = cbBuf;
7382 DWORD shift;
7383 BOOL space = (cbBuf > 0);
7384 LPBYTE ptr = buf;
7385 LPDEVMODEA dmA = NULL;
7386 LPDEVMODEW devmode;
7387
7388 *pcbNeeded = 0;
7389
7390 if(space)
7391 {
7392 ji2->JobId = job->job_id;
7393 }
7394
7395 string_to_buf(job->document_title, ptr, left, &size, unicode);
7396 if(space && size <= left)
7397 {
7398 ji2->pDocument = (LPWSTR)ptr;
7399 ptr += size;
7400 left -= size;
7401 }
7402 else
7403 space = FALSE;
7404 *pcbNeeded += size;
7405
7406 if (job->printer_name)
7407 {
7408 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7409 if(space && size <= left)
7410 {
7411 ji2->pPrinterName = (LPWSTR)ptr;
7412 ptr += size;
7413 left -= size;
7414 }
7415 else
7416 space = FALSE;
7417 *pcbNeeded += size;
7418 }
7419
7420 if (job->devmode)
7421 {
7422 if (!unicode)
7423 {
7424 dmA = DEVMODEdupWtoA(job->devmode);
7425 devmode = (LPDEVMODEW) dmA;
7426 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7427 }
7428 else
7429 {
7430 devmode = job->devmode;
7431 size = devmode->dmSize + devmode->dmDriverExtra;
7432 }
7433
7434 if (!devmode)
7435 FIXME("Can't convert DEVMODE W to A\n");
7436 else
7437 {
7438 /* align DEVMODE to a DWORD boundary */
7439 shift = (4 - (*pcbNeeded & 3)) & 3;
7440 size += shift;
7441
7442 if (size <= left)
7443 {
7444 ptr += shift;
7445 memcpy(ptr, devmode, size-shift);
7446 ji2->pDevMode = (LPDEVMODEW)ptr;
7447 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7448 ptr += size-shift;
7449 left -= size;
7450 }
7451 else
7452 space = FALSE;
7453 *pcbNeeded +=size;
7454 }
7455 }
7456
7457 return space;
7458 }
7459
7460 /*****************************************************************************
7461 * get_job_info
7462 */
7463 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7464 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7465 {
7466 BOOL ret = FALSE;
7467 DWORD needed = 0, size;
7468 job_t *job;
7469 LPBYTE ptr = pJob;
7470
7471 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7472
7473 EnterCriticalSection(&printer_handles_cs);
7474 job = get_job(hPrinter, JobId);
7475 if(!job)
7476 goto end;
7477
7478 switch(Level)
7479 {
7480 case 1:
7481 size = sizeof(JOB_INFO_1W);
7482 if(cbBuf >= size)
7483 {
7484 cbBuf -= size;
7485 ptr += size;
7486 memset(pJob, 0, size);
7487 }
7488 else
7489 cbBuf = 0;
7490 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7491 needed += size;
7492 break;
7493
7494 case 2:
7495 size = sizeof(JOB_INFO_2W);
7496 if(cbBuf >= size)
7497 {
7498 cbBuf -= size;
7499 ptr += size;
7500 memset(pJob, 0, size);
7501 }
7502 else
7503 cbBuf = 0;
7504 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7505 needed += size;
7506 break;
7507
7508 case 3:
7509 size = sizeof(JOB_INFO_3);
7510 if(cbBuf >= size)
7511 {
7512 cbBuf -= size;
7513 memset(pJob, 0, size);
7514 ret = TRUE;
7515 }
7516 else
7517 cbBuf = 0;
7518 needed = size;
7519 break;
7520
7521 default:
7522 SetLastError(ERROR_INVALID_LEVEL);
7523 goto end;
7524 }
7525 if(pcbNeeded)
7526 *pcbNeeded = needed;
7527 end:
7528 LeaveCriticalSection(&printer_handles_cs);
7529 return ret;
7530 }
7531
7532 /*****************************************************************************
7533 * GetJobA [WINSPOOL.@]
7534 *
7535 */
7536 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7537 DWORD cbBuf, LPDWORD pcbNeeded)
7538 {
7539 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7540 }
7541
7542 /*****************************************************************************
7543 * GetJobW [WINSPOOL.@]
7544 *
7545 */
7546 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7547 DWORD cbBuf, LPDWORD pcbNeeded)
7548 {
7549 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7550 }
7551
7552 /*****************************************************************************
7553 * schedule_pipe
7554 */
7555 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7556 {
7557 #ifdef HAVE_FORK
7558 char *unixname, *cmdA;
7559 DWORD len;
7560 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7561 BOOL ret = FALSE;
7562 char buf[1024];
7563 pid_t pid, wret;
7564 int status;
7565
7566 if(!(unixname = wine_get_unix_file_name(filename)))
7567 return FALSE;
7568
7569 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7570 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7571 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7572
7573 TRACE("printing with: %s\n", cmdA);
7574
7575 if((file_fd = open(unixname, O_RDONLY)) == -1)
7576 goto end;
7577
7578 if (pipe(fds))
7579 {
7580 ERR("pipe() failed!\n");
7581 goto end;
7582 }
7583
7584 if ((pid = fork()) == 0)
7585 {
7586 close(0);
7587 dup2(fds[0], 0);
7588 close(fds[1]);
7589
7590 /* reset signals that we previously set to SIG_IGN */
7591 signal(SIGPIPE, SIG_DFL);
7592
7593 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7594 _exit(1);
7595 }
7596 else if (pid == -1)
7597 {
7598 ERR("fork() failed!\n");
7599 goto end;
7600 }
7601
7602 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7603 write(fds[1], buf, no_read);
7604
7605 close(fds[1]);
7606 fds[1] = -1;
7607
7608 /* reap child */
7609 do {
7610 wret = waitpid(pid, &status, 0);
7611 } while (wret < 0 && errno == EINTR);
7612 if (wret < 0)
7613 {
7614 ERR("waitpid() failed!\n");
7615 goto end;
7616 }
7617 if (!WIFEXITED(status) || WEXITSTATUS(status))
7618 {
7619 ERR("child process failed! %d\n", status);
7620 goto end;
7621 }
7622
7623 ret = TRUE;
7624
7625 end:
7626 if(file_fd != -1) close(file_fd);
7627 if(fds[0] != -1) close(fds[0]);
7628 if(fds[1] != -1) close(fds[1]);
7629
7630 HeapFree(GetProcessHeap(), 0, cmdA);
7631 HeapFree(GetProcessHeap(), 0, unixname);
7632 return ret;
7633 #else
7634 return FALSE;
7635 #endif
7636 }
7637
7638 /*****************************************************************************
7639 * schedule_lpr
7640 */
7641 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7642 {
7643 WCHAR *cmd;
7644 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
7645 BOOL r;
7646
7647 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
7648 sprintfW(cmd, fmtW, printer_name);
7649
7650 r = schedule_pipe(cmd, filename);
7651
7652 HeapFree(GetProcessHeap(), 0, cmd);
7653 return r;
7654 }
7655
7656 #ifdef SONAME_LIBCUPS
7657 /*****************************************************************************
7658 * get_cups_jobs_ticket_options
7659 *
7660 * Explicitly set CUPS options based on any %cupsJobTicket lines.
7661 * The CUPS scheduler only looks for these in Print-File requests, and since
7662 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
7663 * parsed.
7664 */
7665 static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
7666 {
7667 FILE *fp = fopen( file, "r" );
7668 char buf[257]; /* DSC max of 256 + '\0' */
7669 const char *ps_adobe = "%!PS-Adobe-";
7670 const char *cups_job = "%cupsJobTicket:";
7671
7672 if (!fp) return num_options;
7673 if (!fgets( buf, sizeof(buf), fp )) goto end;
7674 if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
7675 while (fgets( buf, sizeof(buf), fp ))
7676 {
7677 if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
7678 num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
7679 }
7680
7681 end:
7682 fclose( fp );
7683 return num_options;
7684 }
7685 #endif
7686
7687 /*****************************************************************************
7688 * schedule_cups
7689 */
7690 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7691 {
7692 #ifdef SONAME_LIBCUPS
7693 if(pcupsPrintFile)
7694 {
7695 char *unixname, *queue, *unix_doc_title;
7696 DWORD len;
7697 BOOL ret;
7698 int num_options = 0, i;
7699 cups_option_t *options = NULL;
7700
7701 if(!(unixname = wine_get_unix_file_name(filename)))
7702 return FALSE;
7703
7704 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7705 queue = HeapAlloc(GetProcessHeap(), 0, len);
7706 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7707
7708 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7709 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7710 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7711
7712 num_options = get_cups_job_ticket_options( unixname, num_options, &options );
7713
7714 TRACE( "printing via cups with options:\n" );
7715 for (i = 0; i < num_options; i++)
7716 TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
7717
7718 ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
7719
7720 pcupsFreeOptions( num_options, options );
7721
7722 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7723 HeapFree(GetProcessHeap(), 0, queue);
7724 HeapFree(GetProcessHeap(), 0, unixname);
7725 return ret;
7726 }
7727 else
7728 #endif
7729 {
7730 return schedule_lpr(printer_name, filename);
7731 }
7732 }
7733
7734 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7735 {
7736 LPWSTR filename;
7737
7738 switch(msg)
7739 {
7740 case WM_INITDIALOG:
7741 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7742 return TRUE;
7743
7744 case WM_COMMAND:
7745 if(HIWORD(wparam) == BN_CLICKED)
7746 {
7747 if(LOWORD(wparam) == IDOK)
7748 {
7749 HANDLE hf;
7750 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7751 LPWSTR *output;
7752
7753 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7754 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7755
7756 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7757 {
7758 WCHAR caption[200], message[200];
7759 int mb_ret;
7760
7761 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7762 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7763 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7764 if(mb_ret == IDCANCEL)
7765 {
7766 HeapFree(GetProcessHeap(), 0, filename);
7767 return TRUE;
7768 }
7769 }
7770 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7771 if(hf == INVALID_HANDLE_VALUE)
7772 {
7773 WCHAR caption[200], message[200];
7774
7775 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7776 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7777 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7778 HeapFree(GetProcessHeap(), 0, filename);
7779 return TRUE;
7780 }
7781 CloseHandle(hf);
7782 DeleteFileW(filename);
7783 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7784 *output = filename;
7785 EndDialog(hwnd, IDOK);
7786 return TRUE;
7787 }
7788 if(LOWORD(wparam) == IDCANCEL)
7789 {
7790 EndDialog(hwnd, IDCANCEL);
7791 return TRUE;
7792 }
7793 }
7794 return FALSE;
7795 }
7796 return FALSE;
7797 }
7798
7799 /*****************************************************************************
7800 * get_filename
7801 */
7802 static BOOL get_filename(LPWSTR *filename)
7803 {
7804 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7805 file_dlg_proc, (LPARAM)filename) == IDOK;
7806 }
7807
7808 /*****************************************************************************
7809 * schedule_file
7810 */
7811 static BOOL schedule_file(LPCWSTR filename)
7812 {
7813 LPWSTR output = NULL;
7814
7815 if(get_filename(&output))
7816 {
7817 BOOL r;
7818 TRACE("copy to %s\n", debugstr_w(output));
7819 r = CopyFileW(filename, output, FALSE);
7820 HeapFree(GetProcessHeap(), 0, output);
7821 return r;
7822 }
7823 return FALSE;
7824 }
7825
7826 /*****************************************************************************
7827 * schedule_unixfile
7828 */
7829 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7830 {
7831 int in_fd, out_fd, no_read;
7832 char buf[1024];
7833 BOOL ret = FALSE;
7834 char *unixname, *outputA;
7835 DWORD len;
7836
7837 if(!(unixname = wine_get_unix_file_name(filename)))
7838 return FALSE;
7839
7840 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7841 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7842 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7843
7844 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7845 in_fd = open(unixname, O_RDONLY);
7846 if(out_fd == -1 || in_fd == -1)
7847 goto end;
7848
7849 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7850 write(out_fd, buf, no_read);
7851
7852 ret = TRUE;
7853 end:
7854 if(in_fd != -1) close(in_fd);
7855 if(out_fd != -1) close(out_fd);
7856 HeapFree(GetProcessHeap(), 0, outputA);
7857 HeapFree(GetProcessHeap(), 0, unixname);
7858 return ret;
7859 }
7860
7861 /*****************************************************************************
7862 * ScheduleJob [WINSPOOL.@]
7863 *
7864 */
7865 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7866 {
7867 opened_printer_t *printer;
7868 BOOL ret = FALSE;
7869 struct list *cursor, *cursor2;
7870
7871 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7872 EnterCriticalSection(&printer_handles_cs);
7873 printer = get_opened_printer(hPrinter);
7874 if(!printer)
7875 goto end;
7876
7877 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7878 {
7879 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7880 HANDLE hf;
7881
7882 if(job->job_id != dwJobID) continue;
7883
7884 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7885 if(hf != INVALID_HANDLE_VALUE)
7886 {
7887 PRINTER_INFO_5W *pi5 = NULL;
7888 LPWSTR portname = job->portname;
7889 DWORD needed;
7890 HKEY hkey;
7891 WCHAR output[1024];
7892 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7893 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7894
7895 if (!portname)
7896 {
7897 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7898 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7899 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7900 portname = pi5->pPortName;
7901 }
7902 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7903 debugstr_w(portname));
7904
7905 output[0] = 0;
7906
7907 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7908 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7909 {
7910 DWORD type, count = sizeof(output);
7911 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
7912 RegCloseKey(hkey);
7913 }
7914 if(output[0] == '|')
7915 {
7916 ret = schedule_pipe(output + 1, job->filename);
7917 }
7918 else if(output[0])
7919 {
7920 ret = schedule_unixfile(output, job->filename);
7921 }
7922 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
7923 {
7924 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
7925 }
7926 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
7927 {
7928 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
7929 }
7930 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
7931 {
7932 ret = schedule_file(job->filename);
7933 }
7934 else
7935 {
7936 FIXME("can't schedule to port %s\n", debugstr_w(portname));
7937 }
7938 HeapFree(GetProcessHeap(), 0, pi5);
7939 CloseHandle(hf);
7940 DeleteFileW(job->filename);
7941 }
7942 list_remove(cursor);
7943 HeapFree(GetProcessHeap(), 0, job->document_title);
7944 HeapFree(GetProcessHeap(), 0, job->printer_name);
7945 HeapFree(GetProcessHeap(), 0, job->portname);
7946 HeapFree(GetProcessHeap(), 0, job->filename);
7947 HeapFree(GetProcessHeap(), 0, job->devmode);
7948 HeapFree(GetProcessHeap(), 0, job);
7949 break;
7950 }
7951 end:
7952 LeaveCriticalSection(&printer_handles_cs);
7953 return ret;
7954 }
7955
7956 /*****************************************************************************
7957 * StartDocDlgA [WINSPOOL.@]
7958 */
7959 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7960 {
7961 UNICODE_STRING usBuffer;
7962 DOCINFOW docW;
7963 LPWSTR retW;
7964 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7965 LPSTR ret = NULL;
7966
7967 docW.cbSize = sizeof(docW);
7968 if (doc->lpszDocName)
7969 {
7970 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7971 if (!(docW.lpszDocName = docnameW)) return NULL;
7972 }
7973 if (doc->lpszOutput)
7974 {
7975 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7976 if (!(docW.lpszOutput = outputW)) return NULL;
7977 }
7978 if (doc->lpszDatatype)
7979 {
7980 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7981 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7982 }
7983 docW.fwType = doc->fwType;
7984
7985 retW = StartDocDlgW(hPrinter, &docW);
7986
7987 if(retW)
7988 {
7989 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7990 ret = HeapAlloc(GetProcessHeap(), 0, len);
7991 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7992 HeapFree(GetProcessHeap(), 0, retW);
7993 }
7994
7995 HeapFree(GetProcessHeap(), 0, datatypeW);
7996 HeapFree(GetProcessHeap(), 0, outputW);
7997 HeapFree(GetProcessHeap(), 0, docnameW);
7998
7999 return ret;
8000 }
8001
8002 /*****************************************************************************
8003 * StartDocDlgW [WINSPOOL.@]
8004 *
8005 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8006 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8007 * port is "FILE:". Also returns the full path if passed a relative path.
8008 *
8009 * The caller should free the returned string from the process heap.
8010 */
8011 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8012 {
8013 LPWSTR ret = NULL;
8014 DWORD len, attr;
8015
8016 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8017 {
8018 PRINTER_INFO_5W *pi5;
8019 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8020 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8021 return NULL;
8022 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8023 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8024 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8025 {
8026 HeapFree(GetProcessHeap(), 0, pi5);
8027 return NULL;
8028 }
8029 HeapFree(GetProcessHeap(), 0, pi5);
8030 }
8031
8032 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8033 {
8034 LPWSTR name;
8035
8036 if (get_filename(&name))
8037 {
8038 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8039 {
8040 HeapFree(GetProcessHeap(), 0, name);
8041 return NULL;
8042 }
8043 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8044 GetFullPathNameW(name, len, ret, NULL);
8045 HeapFree(GetProcessHeap(), 0, name);
8046 }
8047 return ret;
8048 }
8049
8050 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8051 return NULL;
8052
8053 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8054 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8055
8056 attr = GetFileAttributesW(ret);
8057 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8058 {
8059 HeapFree(GetProcessHeap(), 0, ret);
8060 ret = NULL;
8061 }
8062 return ret;
8063 }
8064
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.